Azure / azure-functions-durable-extension

Durable Task Framework extension for Azure Functions
MIT License
713 stars 270 forks source link

Durable Entities - Set do not set value #2800

Closed MasterKuat closed 3 months ago

MasterKuat commented 5 months ago

Description

Seems some Signal to durable entities are lost or at least state is out-of-sync.

Here is my entity state get from storage backend (get with Durable function monitor) :

{
   "exists": true,
   "state": {
      "isready": true,
      "isallsatisfied": false,
      "utccreationtime": "2024-04-23T06:54:54.7407339Z",
      "conditions": {
         "381": {
            "CurrentValue": 1,
            "Value": 1,
            "IsSatisfied": true,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 381
         },
         "382": {
            "CurrentValue": 0,
            "Value": 1,
            "IsSatisfied": false,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 382
         },
         "383": {
            "CurrentValue": 1,
            "Value": 1,
            "IsSatisfied": true,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 383
         },
         "384": {
            "CurrentValue": 0,
            "Value": 1,
            "IsSatisfied": false,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 384
         },
         "385": {
            "CurrentValue": 1,
            "Value": 1,
            "IsSatisfied": true,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 385
         },
         "386": {
            "CurrentValue": 0,
            "Value": 1,
            "IsSatisfied": false,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 386
         },
         "387": {
            "CurrentValue": 0,
            "Value": 1,
            "IsSatisfied": false,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 387
         },
         "388": {
            "CurrentValue": 1,
            "Value": 1,
            "IsSatisfied": true,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 388
         },
         "389": {
            "CurrentValue": 0,
            "Value": 1,
            "IsSatisfied": false,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 389
         },
         "390": {
            "CurrentValue": 1,
            "Value": 1,
            "IsSatisfied": true,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 390
         },
         "391": {
            "CurrentValue": 1,
            "Value": 1,
            "IsSatisfied": true,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 391
         },
         "392": {
            "CurrentValue": 1,
            "Value": 1,
            "IsSatisfied": true,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 392
         },
         "393": {
            "CurrentValue": 1,
            "Value": 1,
            "IsSatisfied": true,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 393
         },
         "394": {
            "CurrentValue": 0,
            "Value": 1,
            "IsSatisfied": false,
            "ComparaisonOperator": 1,
            "LoaderConfigId": 394
         }
      },
      "treatment": {
         "ActivityTreatmentParam": {
            "PhaseType": 1,
            "PhaseParam": "{\"Parameters\" : {\"NomDuFlux\": \"RHFluxStartFormation\"}}",
            "BlobUrl": null,
            "Phase": 1
         },
         "StopWarehouseConfig": {
            "WarehouseName": "VWH_DATA_INT",
            "RoleName": "INT_SYSADMIN",
            "Stop": false
         }
      },
      "lifetime": 60
   },
   "sorter": {
      "ReceivedFromInstance": {
         "4d2b68ee-a29f-4280-71b1-061ebb9f5901": {
            "Last": "2024-04-23T06:54:52.7594338Z",
            "ExecutionId": "f7b708a498594cdc98271df56326c0cb"
         },
         "ac4e3b2e-6468-48b2-78c5-e2aba782165e": {
            "Last": "2024-04-23T06:54:53.0807931Z",
            "ExecutionId": "500dd1c211e74056ab1d309c847e8714"
         },
         "ef01acd9-de49-4d07-4e36-43320b940011": {
            "Last": "2024-04-23T06:54:53.5980726Z",
            "ExecutionId": "7b52369ed1924fb4b55e885d27a22d37"
         },
         "f0b64073-ceed-4b26-5192-a8909f1b162f": {
            "Last": "2024-04-23T06:54:54.0325456Z",
            "ExecutionId": "4d7ec467996a4587b33b6c8ec6c52bf6"
         },
         "d3457600-9e2a-4729-5cdf-1d50a639f0ad": {
            "Last": "2024-04-23T06:54:54.3129687Z",
            "ExecutionId": "4409ba6826d14f0491f3616734411ab2"
         },
         "8d1b14ce-e4a4-469e-6c7d-4b332a95aa97": {
            "Last": "2024-04-23T06:54:54.808436Z",
            "ExecutionId": "3f5b8d533e9e4e659a4bc1388be4d133"
         },
         "a74a18ff-f101-470b-7b0b-c0a595d4762e": {
            "Last": "2024-04-23T06:54:52.9370294Z",
            "ExecutionId": "93b42a4ecc264c2fa1378956f9cc215e"
         },
         "c112bbc6-8f14-4b7f-5bd7-16ecb8d7d606": {
            "Last": "2024-04-23T06:54:54.8174246Z",
            "ExecutionId": "8eebce5355a043da8fbb09a9fd159f00"
         },
         "f0f66915-307e-4f2a-5cf3-54211b0ef67c": {
            "Last": "2024-04-23T06:54:54.836728Z",
            "ExecutionId": "2a7b1546abfb4867820ef61b35354980"
         },
         "0dc82db7-0245-45ce-5449-15d947f303d6": {
            "Last": "2024-04-23T06:54:54.8199562Z",
            "ExecutionId": "f783998adba4486993cbc8fd2d1859c2"
         },
         "9d7d6944-53fe-4c77-51db-60004a47a341": {
            "Last": "2024-04-23T06:54:55.3370767Z",
            "ExecutionId": "6e679cc2faa94472b513cff5cdd3b26d"
         },
         "7c532040-f0f6-4782-6e02-a0008d2fcb57": {
            "Last": "2024-04-23T06:54:55.8942373Z",
            "ExecutionId": "3d338d0d0e394860885c0c3524c4b521"
         },
         "5d352275-67ad-41b4-5318-de6937bafcf0": {
            "Last": "2024-04-23T06:54:56.936879Z",
            "ExecutionId": "7497a52ea7aa403a8611af6f4fc51cd0"
         },
         "154bb9a5-bf5f-4349-7eb3-bd1dcf27531c": {
            "Last": "2024-04-23T06:54:57.0181064Z",
            "ExecutionId": "060b09ad81a643d6889bb74cee8ebf0a"
         }
      },
      "ReceiveHorizon": "2024-04-23T06:24:49.3408366Z"
   }
}

All orchestration id in ReceivedFromInstance set different ConfigID. For exemple, instance id a74a18ff-f101-470b-7b0b-c0a595d4762e set Confid 386. I'm able to see the set input in orchestration as :

{"$type":"Microsoft.Azure.WebJobs.Extensions.DurableTask.RequestMessage, Microsoft.Azure.WebJobs.Extensions.DurableTask","op":"Set","input":"386","id":"139d48e4-5397-5d49-8091-482b7d856a43","parent":"a74a18ff-f101-470b-7b0b-c0a595d4762e","parentExecution":"93b42a4ecc264c2fa1378956f9cc215e","Timestamp":"2024-04-23T06:54:52.9370294Z","Predecessor":"2024-04-23T06:54:52.7807628Z"}

Obviously, currentvalue is not incremented for this configId ("CurrentValue": 0) or at least state is not updated.

Expected behavior

All curentValue should be 1 and "CheckAllSatisfied" should return true and then start new orchestration.

Actual behavior

Not all currentValue are set to 1 even if all confID are called. Nevertheless, if a setup my orchestration with 2 or 3 condition, it's working fine.

Relevant source code snippets

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class Counter : ICounter
{ 
[...]
        public Task Set(int configId)
        {
            if (!Conditions.ContainsKey(configId))
            {
                return Task.CompletedTask;
            }
            Condition cond = Conditions[configId];
            cond.CurrentValue += 1;
            cond.IsSatisfied = cond.ComparaisonOperator switch
            {
                CriteriaOperator.EQ => cond.CurrentValue == cond.Value,
                CriteriaOperator.NE => cond.CurrentValue != cond.Value,
                CriteriaOperator.GT => cond.CurrentValue > cond.Value,
                CriteriaOperator.LT => cond.CurrentValue > cond.Value,
                CriteriaOperator.GE => cond.CurrentValue >= cond.Value,
                CriteriaOperator.LE => cond.CurrentValue <= cond.Value,
                CriteriaOperator.None => true,
                _ => true
            };
            if (CheckAllSatisfied()) {
                string instanceId = $"{Guid.NewGuid()}-{Microsoft.Azure.WebJobs.Extensions.DurableTask.Entity.Current.EntityKey}";
                Microsoft.Azure.WebJobs.Extensions.DurableTask.Entity.Current.StartNewOrchestration("CounterOrchestrator", OrchestratorParam, instanceId);
                Delete();
            }
            return Task.CompletedTask;
        }
        private bool CheckAllSatisfied()
        {
            var res = true;
            foreach (var cond in Conditions.Values)
            {
                res &= cond.IsSatisfied;
            }
            IsAllSatisfied = res;
            return res;
        }
}

App Details

If deployed to Azure

We have access to a lot of telemetry that can help with investigations. Please provide as much of the following information as you can to help us investigate!

If you don't want to share your Function App or storage account name GitHub, please at least share the orchestration instance ID. Otherwise it's extremely difficult to look up information.

MasterKuat commented 5 months ago

For the records, my issue sound close to https://github.com/Azure/azure-functions-durable-extension/issues/2744 except my function model is in-process

MasterKuat commented 3 months ago

Fixed in version 2.13.4 and there was also a race condition issue. On this latest point documentation is unclear : "To prevent conflicts, all operations on a single entity are guaranteed to execute serially, that is, one after another."