Home > Blockchain >  Azure function return unique sequence number
Azure function return unique sequence number

Time:11-18

I am new to Azure. I would like to create a function that returns the sequence number. I have created a function using Thread mutex to lock the sequence number. I tested the below code with around 10k parallel requests. The problem is I am getting duplicates sequence number when doing the testing, mutex is not working. I am not sure what to do to avoid duplication instead generate running number for each request

Public class MySharedMutexCounter { 
  public static long count = 0; 
  public static Mutex ObjMutex = new Mutex(false,"SeqGenerator"); 
}  

public long GetSequnceNo(){
    long seqId = -1;
    
    try{
     MySharedMutexCounter.ObjMutex.waitOne();
     seqId =    MySharedMutexCounter.count;
     if(seqId > 100){
       MySharedMutexCounter.count = 0;
       seqId =    MySharedMutexCounter.count;
     }
     return seqId;
    }finally{
      MySharedMutexCounter.ObjMutex.RelaseMutex();
    }
    return -1;
}

CodePudding user response:

Thing is, an azure function can scale to multiple instances running on different machines so you need a distributed lock of some kind or another way to guarantee there won't be concurrent access to the state.

How about using a Durable Entity? It is basically a piece of state that can be accessed by a Durable Function and operations against the state are performed in a safe way:

To prevent conflicts, all operations on a single entity are guaranteed to execute serially, that is, one after another.

(source)

A durable entity is like a distributed object, so other instances of the function will use the same entity.

The Developer Guide demonstrates a nice example using a counter. Kind of fits your scenario.

CodePudding user response:

Hi @Peter Bons I tried the below code but taking lot of time. May be something wrong in my code. Is it possible to get the value in a fraction of second bcos I shd return the value less than a second.

    [FunctionName("FunctionOrchestrator")]
    public static async Task<int> RunOrchestrator(
        [OrchestrationTrigger] IDurableOrchestrationContext context)
    {
        int currentValue = -1;
        var input = context.GetInput<CounterParameter>();

        if (input != null && !string.IsNullOrWhiteSpace(input.OperationName))
        {
    
            var entityId = new EntityId("Counter", "myCounter");

            // Perform the requested operation on the entity
            currentValue = await context.CallEntityAsync<int>(entityId, input.OperationName);
        }

        return currentValue;
    }

    [FunctionName("Counter")]
    public static int Counter([EntityTrigger] IDurableEntityContext ctx, ILogger log)
    {
        log.LogInformation($"Request for operation {ctx.OperationName} on entity.");

            switch (ctx.OperationName.Trim().ToLowerInvariant())
            {
                case "increment":
                    ctx.SetState(ctx.GetState<int>()   1);
                    break;
             }
        
    // Return the latest value
    return ctx.GetState<int>();
    }

    [FunctionName("AutoIncrement")]
    public static async Task<HttpResponseMessage> HttpAutoIncrement(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
        [DurableClient] IDurableOrchestrationClient starter,
        [DurableClient] IDurableEntityClient client,
        ILogger log)

    {

        // Function input comes from the request content.
        var input = new CounterParameter { OperationName = "Increment" };
        string instanceId = await starter.StartNewAsync("FunctionOrchestrator", input);

        log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
        await starter.WaitForCompletionOrCreateCheckStatusResponseAsync(req, instanceId);

        var entityId = new EntityId("Counter", "myCounter");

        try
        {
            // An error will be thrown if the counter is not initialised.
            var stateResponse = await client.ReadEntityStateAsync<int>(entityId);
            return new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent(stateResponse.EntityState.ToString())
            };
        }
        catch (System.NullReferenceException)
        {
            return new HttpResponseMessage(HttpStatusCode.NotFound)
            {
                Content = new StringContent("Counter is not yet initialised. "  
                "Initialise it by calling increment or decrement HTTP Function.")
            };
        }
    }
  • Related