1

We have a business scenario where a client sends us a request, then our backend service inserts multiple documents at the same time and returns the most recent CosmosDB's session token. The logic looks roughly similar to this:

// Controller Code
[HttpPost]
public async Task<IActionResult> Demo([FromBody] User[] users)
{
  // Create multiple documents here
  var tasks = new List<Task>();
  foreach(var user in users)
  {
    tasks.add(this.container.CreateItemAsync(user, new PartitionKey("my partitionKey")));
  }
  
  // task when all returns an array of ItemResponses
  ItemResponse<User> [] usersItemResponses = await Task.WhenAll(tasks); 
  
  // I could extract the session tokens associated with each ItemResponse
  List<string> sessionTokens = usersItemResponses.Select(response => response.Headers.Session)


  // Here I would like to return the newest session token to the client side, but because the tasks were executed in parallel, I wouldn't know which request finished last, and therefore no way to get the latest session token.
  string sessionTokenString;
  return this.Ok(sessionTokenString);
}

However, I cannot find documentation for how to compare session tokens, and I do not want to do these write operations in sequence.

How do we go about comparing the session tokens of these write operations and return the latest session token to our client so that they can read the db data in subsequent requests?

blueishpoop
  • 226
  • 1
  • 10
  • Not quite sure what you're trying to achieve; it might be best to edit your question with more specifics, along with what you've done so far. Also FYI there are no distributed locks for Cosmos DB; transactions don't span across operations. The only scenario where you can have multiple operations in a single transaction is within a stored procedure. – David Makogon Mar 25 '21 at 14:16
  • @DavidMakogon Thanks! I've added sample code to the question. – blueishpoop Mar 26 '21 at 03:10

1 Answers1

1

You don't need to compare the session token yourself. Flow the session token returned in the response header for a request to the end user then pass it back in the request options to ensure users are reading their own writes.

For a sample see, Utilize session tokens

Updating here because comments are too short.

For your scenario where each user is sending a batch of writes you can manage the session token yourself and compare. The format for the session token is

{pkrangeid}:{Version}#{GlobalLSN}#{RegionId1}={LocalLsn1}#{RegionId2}={LocalLsn2}....#{RegionIdN}={LocalLsnN}. 

However, if you're going to manually check this, you're basically doing a distributed lock which will impact performance. If what you really need is to always get the latest data then you can use Bounded Staleness consistency. BS does a 2 replica read and compares the LSNs for you. If they match the data is the latest, if they don't match, it returns data with the higher LSN. Since all writes are to three replicas you will always get the latest data. The only drawback is reads are 2x that of session consistency because it's a 2 replica read. However, much simpler than what you're suggesting to do.

Mark Brown
  • 8,113
  • 2
  • 17
  • 21
  • Sorry for not being clear before. I've edited the question with code sample. Please take a look, thanks! – blueishpoop Mar 26 '21 at 03:10
  • Not exactly sure but this may be what you're looking for. https://stackoverflow.com/questions/26839809/getting-return-values-from-task-whenall – Mark Brown Mar 27 '21 at 02:39
  • Thanks for the answer. I do know how to get the session tokens out of a `Task.WhenAll` method, but I'm still confused about how to return the latest/newest session token to the client. I've updated the question's code sample to reflect that, please take a look! Thanks! – blueishpoop Mar 27 '21 at 20:26
  • Did you try Task>? – Mark Brown Mar 28 '21 at 02:27
  • I have a lot of session tokens from the insert operations I did. I need to give the client something (a session token perhaps) so that when the client makes the requests again and brings that session token, it will see the the data we inserted in the previous operation. But again, the problem is that we have A LIST of session tokens, but the RequestOptions API takes a SINGLE session token. Unless I've missed something in the documentation. – blueishpoop Mar 28 '21 at 07:59
  • Just return the last one in the list. – Mark Brown Mar 28 '21 at 15:40
  • The last session token in the list doesn't mean that it is from the last operation that cosmos DB processed, because the all operations get executed concurrently. Which is I why I asked for whether there is a way to compare the tokens, so that I can ensure the token I return to the client is always the latest one. – blueishpoop Mar 28 '21 at 17:48
  • See updated answer. My suggestion is to not use the session tokens. They are best when the token can be flowed back and forth with single item writes or updates. Thanks. – Mark Brown Mar 29 '21 at 18:12
  • Thanks for the answer! If I were to compare the session token instead of using the bounded staleness session. Do I always have to get the largest value for pkrangeid,Version,GlobalLSN and LocalLsns? – blueishpoop Mar 30 '21 at 08:40