0

I am using Cosmos DB and wanted to implement a user friendly id for displaying in UI for end user. For this what I am doing is taking max ID existing in DB and adding 1 to it .

The problem that I am facing over here is when multiple user hit this function the max id returned is same and the new ID generated is getting duplicated.

how can I make sure that a certain block of code is only executed one at a time.

I tried SemaphoreSlim , didn't help. I am expecting to generate auto incremented ID without any duplication .

David Makogon
  • 69,407
  • 21
  • 141
  • 189
  • 2
    The quick answer is: just don't. Theoretically it's possible with some effort, but you're just inviting race conditions and performance traps into your code for little benefit. Maybe there is some other unique property on your documents that can be used as the id? Might also be a combination of multiple properties. – Good Night Nerd Pride Nov 15 '22 at 09:22
  • AFAIK CosmosDB does not have auto-incremented columns by design, but triggers might be a way around that if you really want them. See: https://stackoverflow.com/questions/27699928/how-to-create-a-auto-incremented-column-in-documentdb – Good Night Nerd Pride Nov 15 '22 at 09:26
  • It might be that you're semaphore does not work because your CosmosDB service/repository (or whichever class owns the semaphore) is newly instantiated for every user request. Try to register it as a singleton. – Good Night Nerd Pride Nov 15 '22 at 09:29
  • Queue the request for the id... – Peter Bons Nov 15 '22 at 09:31
  • What's the purpose of the Id, what's it used for? Warm cosy feeling, or do they actually copy it and use it somewhere else? If they are not specifically used elsewhere, I use Guids and then display the last x digits on any display screen. The backend uses the Guids and the front end shows some nicer formatted numbers. – MrC aka Shaun Curtis Nov 15 '22 at 10:27
  • @MrCakaShaunCurtis , These Id's are used as a reference by the user , and We need it to be in sequential order and not random . – CSharp User Nov 15 '22 at 10:31
  • I'm with @GoodNightNerdPride first comment here. You can put a management layer on the front of your database in a singleton service and make all your calls into that. Make the insert call async with the task returning the new ID. Internally it runs a queue. But you can always inadvertently end up with multiple management layers running. – MrC aka Shaun Curtis Nov 15 '22 at 16:00

3 Answers3

0

What about if you use lock ?

Declare:

private readonly object _threadLock = new object();
private int counter;

Use it:

       lock (_threadLock)
        {
            // put your thread safe code here.
            counter++;
        }
n-azad
  • 69
  • 5
0

Cosmos DB does not provide an auto-increment id feature because it is impossible to do so with a database like this one while maintaining scalability. The first comment to your question is the best one, just don't use them. Anything you implement to do this will always be a performance bottleneck and your database will never scale. Also, if you try to scale out and use multiple SDK instances, any mutex you implement would now force you to re-implement as a distributed mutex across multiple compute instances making performance even worse.

If the container is designed to be a key-value store, find one or more properties that guarantee uniqueness, then use that as your id (and partition key as well). This can still provide the user some amount of human readability while providing the uniqueness you are looking for.

Mark Brown
  • 8,113
  • 2
  • 17
  • 21
  • Currently I don't have control over DB configuration . And it is mandated to use a different field and keep it auto incremented. As per your suggestion for a low user frequency system will Mutex solve the issue ? I already implemented SemaphoreSlim and still geting duplicate id in production. – CSharp User Nov 15 '22 at 14:15
  • You need an exclusive lock (mutex) on the resource that looks up the max id, increments it, then inserts it into the database such that you can read it back out when the next insert is to be made. – Mark Brown Nov 15 '22 at 20:32
  • Thanks for the explanation . My mistake was I used Semaphore at local scope of the function. So each time a user was requesting that resource a new object was getting instantiated , due to which multiple access was getting granted. But now that I have made my Object creation static at class level , it is working as expected. – CSharp User Nov 16 '22 at 10:59
0

What I did is created a function that gets the max MeaningfulID from DB , and the next time i pass the insert operation , I add 1 to it.

My mistake was I instantiated semaphore at local scope. Now that it is mate static and at class level , even if multiple user access it, it waits until previous thread is completed.