From 02cad73af063612ea9b9a0e2c08d62cd97d63f5a Mon Sep 17 00:00:00 2001 From: Ankit Sarkar Date: Tue, 14 Jul 2020 18:54:07 +0530 Subject: [PATCH] fix#227: Add Azure Blob Storage distributed lock provider (#332) * Fix#325:Elsa 2#RunWorkflowDefinitionAsync getting object reference null * Fix#328: Rephrased error message * activityId should not be mandatory while using RunWorkflowDefinitionAsync * Fix#228:Add Redis distributed lock provider * Removed unnecessary namespaces * fix#227: Add Azure Blob Storage distributed lock provider * Fix#228: Add Redis distributed lock provider, Re-architeched the soultion which includes - Remove of StartAsync - Auto Recover of Transient error * fix#227: Add Azure Blob Storage distributed lock provider, Contains below enhancement - - Removed dependency of DistributedLockProvider - Better Log management * Fix#228: Add Redis distributed lock provider, This includes below enhqncement - Better Log Management, - Return false instead of throwing error in while unable to acquire lock * fix#227: Add Azure Blob Storage distributed lock provider , This includes - Validate name before creating lease * fix#227: Add Azure Blob Storage distributed lock provider updated message for ILogger * fix#227: Moved literal values into a constant field, added Azure Lease Blob link for reference Co-authored-by: Ankit Sarkar --- Samples.sln | 561 +++++++++--------- .../HostedServices/TimersHostedService.cs | 6 +- .../IDistributedLockProvider.cs | 3 +- .../DefaultLockProvider.cs | 4 +- src/core/Elsa.Core/ElsaOptions.cs | 7 +- .../ResumeRunningWorkflowsTask.cs | 7 +- .../AzureBlobLockProvider.cs | 204 +++++++ .../Elsa.DistributedLocking.AzureBlob.csproj | 16 + .../ElsaOptionsExtensions.cs | 19 + .../LockedBlob.cs | 22 + .../Elsa.DistributedLocking.Redis.csproj | 16 + .../ElsaOptionsExtensions.cs | 45 ++ .../RedisLockProvider.cs | 99 ++++ .../SqlLockProvider.cs | 16 +- .../Elsa.Samples.DistributedLock.csproj | 21 + .../Elsa.Samples.DistributedLock/Program.cs | 36 ++ .../RecurringWorkflow.cs | 22 + 17 files changed, 815 insertions(+), 289 deletions(-) rename src/core/Elsa.Abstractions/{Services => DistributedLock}/IDistributedLockProvider.cs (95%) rename src/core/Elsa.Core/{Services => DistributedLock}/DefaultLockProvider.cs (96%) create mode 100644 src/providers/Elsa.DistributedLocking.AzureBlob/AzureBlobLockProvider.cs create mode 100644 src/providers/Elsa.DistributedLocking.AzureBlob/Elsa.DistributedLocking.AzureBlob.csproj create mode 100644 src/providers/Elsa.DistributedLocking.AzureBlob/ElsaOptionsExtensions.cs create mode 100644 src/providers/Elsa.DistributedLocking.AzureBlob/LockedBlob.cs create mode 100644 src/providers/Elsa.DistributedLocking.Redis/Elsa.DistributedLocking.Redis.csproj create mode 100644 src/providers/Elsa.DistributedLocking.Redis/ElsaOptionsExtensions.cs create mode 100644 src/providers/Elsa.DistributedLocking.Redis/RedisLockProvider.cs create mode 100644 src/samples/Elsa.Samples.DistributedLock/Elsa.Samples.DistributedLock.csproj create mode 100644 src/samples/Elsa.Samples.DistributedLock/Program.cs create mode 100644 src/samples/Elsa.Samples.DistributedLock/RecurringWorkflow.cs diff --git a/Samples.sln b/Samples.sln index c7ea95f7d..9eb8a4f82 100644 --- a/Samples.sln +++ b/Samples.sln @@ -1,270 +1,291 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29509.3 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core", "src\core\Elsa.Core\Elsa.Core.csproj", "{300EE2D5-54C5-46F2-AD03-BB43589EA074}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{7165BB9E-F22C-40D2-B7B1-CA3EFA2529A0}" - ProjectSection(SolutionItems) = preProject - .dockerignore = .dockerignore - .editorconfig = .editorconfig - .gitignore = .gitignore - docker-compose.yaml = docker-compose.yaml - Dockerfile = Dockerfile - Nuget.Config = Nuget.Config - README.md = README.md - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Abstractions", "src\core\Elsa.Abstractions\Elsa.Abstractions.csproj", "{3130C574-557C-4DA2-933E-AED7A9EBE48A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{35F44BE9-13D0-417C-A01A-F0787BEE6DC3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Console", "src\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj", "{B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Http", "src\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj", "{1D63E1B4-2386-4BEC-9090-C3F3CBF25703}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "activities", "activities", "{B43B546E-23F3-46E8-ACB7-D04F05CDA180}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Email", "src\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj", "{D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Timers", "src\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj", "{E4B71DC4-3E73-49C3-9B4E-CA13909F222D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.MassTransit", "src\activities\Elsa.Activities.MassTransit\Elsa.Activities.MassTransit.csproj", "{C4939482-9447-47D1-B6AF-E9F8C6323841}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5E5E1E84-DDBC-40D6-B891-0D563A15A44A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "providers", "providers", "{600C4AE0-0585-4181-9CEC-2BB43430C713}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.UserTask", "src\activities\Elsa.Activities.UserTask\Elsa.Activities.UserTask.csproj", "{823F80B6-E241-43F7-83BD-29FBB58A77F9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Dropbox", "src\activities\Elsa.Activities.Dropbox\Elsa.Activities.Dropbox.csproj", "{79E85459-EF54-44D6-9508-1E68B8238D00}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripting", "scripting", "{9C3C685E-3D7D-4638-A031-24F71CF74B52}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa", "src\core\Elsa\Elsa.csproj", "{6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Scripting.JavaScript", "src\scripting\Elsa.Scripting.JavaScript\Elsa.Scripting.JavaScript.csproj", "{18BE8F72-E528-4617-B1B1-07BD35337DFC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Scripting.Liquid", "src\scripting\Elsa.Scripting.Liquid\Elsa.Scripting.Liquid.csproj", "{01DC21DD-C6E2-4B21-864E-97D29448F777}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Reflection", "src\activities\Elsa.Activities.Reflection\Elsa.Activities.Reflection.csproj", "{258F624E-98D7-4498-AE2E-F612D8ECA763}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "server", "server", "{468E498C-59DB-4541-8D8A-0D89DE9083AB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Core", "src\server\Elsa.Server.Core\Elsa.Server.Core.csproj", "{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Host", "src\server\Elsa.Server.Host\Elsa.Server.Host.csproj", "{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AB1AE008-6FD6-414C-8E88-D735F42E1FA6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core.UnitTests", "test\unit\Elsa.Core.UnitTests\Elsa.Core.UnitTests.csproj", "{475EEB95-ED27-4366-88EA-97C5000AC8E8}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Testing.Shared", "test\shared\Elsa.Testing.Shared\Elsa.Testing.Shared.csproj", "{E7C689EB-5AD6-4E91-A007-6116EEA702FC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.DocumentDb", "src\providers\Elsa.Persistence.DocumentDb\Elsa.Persistence.DocumentDb.csproj", "{C042677F-973C-4672-AFA1-31B389962FE5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.EntityFrameworkCore", "src\providers\Elsa.Persistence.EntityFrameworkCore\Elsa.Persistence.EntityFrameworkCore.csproj", "{3F43514A-927E-4C62-B153-AFCAD7B1A7FC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.MongoDb", "src\providers\Elsa.Persistence.MongoDb\Elsa.Persistence.MongoDb.csproj", "{36A6F881-1B40-438D-9B6D-80F01CE76D51}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.YesSql", "src\providers\Elsa.Persistence.YesSql\Elsa.Persistence.YesSql.csproj", "{DA825F41-EE97-47B3-801E-C694A6C53AEC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Timers", "src\samples\Elsa.Samples.Timers\Elsa.Samples.Timers.csproj", "{071DD6EC-D00C-4513-82B6-3FE8438061E3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.SqlServer", "src\providers\Elsa.DistributedLocking.SqlServer\Elsa.DistributedLocking.SqlServer.csproj", "{150EF356-E8BC-4922-91C2-362017479409}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.GraphQL", "src\server\Elsa.Server.GraphQL\Elsa.Server.GraphQL.csproj", "{12D29DDC-A885-4CAA-908C-106D845B10C0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Serialization", "src\samples\Elsa.Samples.Serialization\Elsa.Samples.Serialization.csproj", "{DF47517F-9029-44DF-A29F-F2DE15041473}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.HelloWorldConsole", "src\samples\Elsa.Samples.HelloWorldConsole\Elsa.Samples.HelloWorldConsole.csproj", "{E224F8CF-F9F5-4E99-B405-758F3C02C47A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.HelloWorldHttp", "src\samples\Elsa.Samples.HelloWorldHttp\Elsa.Samples.HelloWorldHttp.csproj", "{A11D79AE-F4C9-4595-9B73-0E0AB221B90D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.CustomActivities", "src\samples\Elsa.Samples.CustomActivities\Elsa.Samples.CustomActivities.csproj", "{554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.TimesheetApproval", "src\samples\Elsa.Samples.TimesheetApproval\Elsa.Samples.TimesheetApproval.csproj", "{1678743A-9095-4683-8DCD-5763F41924E2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.WorkflowDefinition", "src\samples\Elsa.Samples.WorkflowDefinition\Elsa.Samples.WorkflowDefinition.csproj", "{7AC91435-7D10-4353-9064-598A6F8EAED6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {300EE2D5-54C5-46F2-AD03-BB43589EA074}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {300EE2D5-54C5-46F2-AD03-BB43589EA074}.Debug|Any CPU.Build.0 = Debug|Any CPU - {300EE2D5-54C5-46F2-AD03-BB43589EA074}.Release|Any CPU.ActiveCfg = Release|Any CPU - {300EE2D5-54C5-46F2-AD03-BB43589EA074}.Release|Any CPU.Build.0 = Release|Any CPU - {3130C574-557C-4DA2-933E-AED7A9EBE48A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3130C574-557C-4DA2-933E-AED7A9EBE48A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3130C574-557C-4DA2-933E-AED7A9EBE48A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3130C574-557C-4DA2-933E-AED7A9EBE48A}.Release|Any CPU.Build.0 = Release|Any CPU - {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}.Release|Any CPU.Build.0 = Release|Any CPU - {1D63E1B4-2386-4BEC-9090-C3F3CBF25703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1D63E1B4-2386-4BEC-9090-C3F3CBF25703}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1D63E1B4-2386-4BEC-9090-C3F3CBF25703}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1D63E1B4-2386-4BEC-9090-C3F3CBF25703}.Release|Any CPU.Build.0 = Release|Any CPU - {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}.Release|Any CPU.Build.0 = Release|Any CPU - {E4B71DC4-3E73-49C3-9B4E-CA13909F222D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4B71DC4-3E73-49C3-9B4E-CA13909F222D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4B71DC4-3E73-49C3-9B4E-CA13909F222D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4B71DC4-3E73-49C3-9B4E-CA13909F222D}.Release|Any CPU.Build.0 = Release|Any CPU - {C4939482-9447-47D1-B6AF-E9F8C6323841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C4939482-9447-47D1-B6AF-E9F8C6323841}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C4939482-9447-47D1-B6AF-E9F8C6323841}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C4939482-9447-47D1-B6AF-E9F8C6323841}.Release|Any CPU.Build.0 = Release|Any CPU - {823F80B6-E241-43F7-83BD-29FBB58A77F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {823F80B6-E241-43F7-83BD-29FBB58A77F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {823F80B6-E241-43F7-83BD-29FBB58A77F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {823F80B6-E241-43F7-83BD-29FBB58A77F9}.Release|Any CPU.Build.0 = Release|Any CPU - {79E85459-EF54-44D6-9508-1E68B8238D00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {79E85459-EF54-44D6-9508-1E68B8238D00}.Debug|Any CPU.Build.0 = Debug|Any CPU - {79E85459-EF54-44D6-9508-1E68B8238D00}.Release|Any CPU.ActiveCfg = Release|Any CPU - {79E85459-EF54-44D6-9508-1E68B8238D00}.Release|Any CPU.Build.0 = Release|Any CPU - {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Release|Any CPU.Build.0 = Release|Any CPU - {18BE8F72-E528-4617-B1B1-07BD35337DFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {18BE8F72-E528-4617-B1B1-07BD35337DFC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {18BE8F72-E528-4617-B1B1-07BD35337DFC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {18BE8F72-E528-4617-B1B1-07BD35337DFC}.Release|Any CPU.Build.0 = Release|Any CPU - {01DC21DD-C6E2-4B21-864E-97D29448F777}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {01DC21DD-C6E2-4B21-864E-97D29448F777}.Debug|Any CPU.Build.0 = Debug|Any CPU - {01DC21DD-C6E2-4B21-864E-97D29448F777}.Release|Any CPU.ActiveCfg = Release|Any CPU - {01DC21DD-C6E2-4B21-864E-97D29448F777}.Release|Any CPU.Build.0 = Release|Any CPU - {258F624E-98D7-4498-AE2E-F612D8ECA763}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {258F624E-98D7-4498-AE2E-F612D8ECA763}.Debug|Any CPU.Build.0 = Debug|Any CPU - {258F624E-98D7-4498-AE2E-F612D8ECA763}.Release|Any CPU.ActiveCfg = Release|Any CPU - {258F624E-98D7-4498-AE2E-F612D8ECA763}.Release|Any CPU.Build.0 = Release|Any CPU - {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.Build.0 = Release|Any CPU - {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.Build.0 = Release|Any CPU - {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.Build.0 = Release|Any CPU - {E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.Build.0 = Release|Any CPU - {C042677F-973C-4672-AFA1-31B389962FE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C042677F-973C-4672-AFA1-31B389962FE5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C042677F-973C-4672-AFA1-31B389962FE5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C042677F-973C-4672-AFA1-31B389962FE5}.Release|Any CPU.Build.0 = Release|Any CPU - {3F43514A-927E-4C62-B153-AFCAD7B1A7FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3F43514A-927E-4C62-B153-AFCAD7B1A7FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3F43514A-927E-4C62-B153-AFCAD7B1A7FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3F43514A-927E-4C62-B153-AFCAD7B1A7FC}.Release|Any CPU.Build.0 = Release|Any CPU - {36A6F881-1B40-438D-9B6D-80F01CE76D51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {36A6F881-1B40-438D-9B6D-80F01CE76D51}.Debug|Any CPU.Build.0 = Debug|Any CPU - {36A6F881-1B40-438D-9B6D-80F01CE76D51}.Release|Any CPU.ActiveCfg = Release|Any CPU - {36A6F881-1B40-438D-9B6D-80F01CE76D51}.Release|Any CPU.Build.0 = Release|Any CPU - {DA825F41-EE97-47B3-801E-C694A6C53AEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DA825F41-EE97-47B3-801E-C694A6C53AEC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DA825F41-EE97-47B3-801E-C694A6C53AEC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DA825F41-EE97-47B3-801E-C694A6C53AEC}.Release|Any CPU.Build.0 = Release|Any CPU - {071DD6EC-D00C-4513-82B6-3FE8438061E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {071DD6EC-D00C-4513-82B6-3FE8438061E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {071DD6EC-D00C-4513-82B6-3FE8438061E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {071DD6EC-D00C-4513-82B6-3FE8438061E3}.Release|Any CPU.Build.0 = Release|Any CPU - {150EF356-E8BC-4922-91C2-362017479409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {150EF356-E8BC-4922-91C2-362017479409}.Debug|Any CPU.Build.0 = Debug|Any CPU - {150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.ActiveCfg = Release|Any CPU - {150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.Build.0 = Release|Any CPU - {12D29DDC-A885-4CAA-908C-106D845B10C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {12D29DDC-A885-4CAA-908C-106D845B10C0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {12D29DDC-A885-4CAA-908C-106D845B10C0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {12D29DDC-A885-4CAA-908C-106D845B10C0}.Release|Any CPU.Build.0 = Release|Any CPU - {DF47517F-9029-44DF-A29F-F2DE15041473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF47517F-9029-44DF-A29F-F2DE15041473}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF47517F-9029-44DF-A29F-F2DE15041473}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DF47517F-9029-44DF-A29F-F2DE15041473}.Release|Any CPU.Build.0 = Release|Any CPU - {E224F8CF-F9F5-4E99-B405-758F3C02C47A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E224F8CF-F9F5-4E99-B405-758F3C02C47A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E224F8CF-F9F5-4E99-B405-758F3C02C47A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E224F8CF-F9F5-4E99-B405-758F3C02C47A}.Release|Any CPU.Build.0 = Release|Any CPU - {A11D79AE-F4C9-4595-9B73-0E0AB221B90D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A11D79AE-F4C9-4595-9B73-0E0AB221B90D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A11D79AE-F4C9-4595-9B73-0E0AB221B90D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A11D79AE-F4C9-4595-9B73-0E0AB221B90D}.Release|Any CPU.Build.0 = Release|Any CPU - {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}.Release|Any CPU.Build.0 = Release|Any CPU - {1678743A-9095-4683-8DCD-5763F41924E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1678743A-9095-4683-8DCD-5763F41924E2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1678743A-9095-4683-8DCD-5763F41924E2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1678743A-9095-4683-8DCD-5763F41924E2}.Release|Any CPU.Build.0 = Release|Any CPU - {7AC91435-7D10-4353-9064-598A6F8EAED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7AC91435-7D10-4353-9064-598A6F8EAED6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7AC91435-7D10-4353-9064-598A6F8EAED6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7AC91435-7D10-4353-9064-598A6F8EAED6}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {300EE2D5-54C5-46F2-AD03-BB43589EA074} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3} - {3130C574-557C-4DA2-933E-AED7A9EBE48A} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3} - {35F44BE9-13D0-417C-A01A-F0787BEE6DC3} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} - {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} - {1D63E1B4-2386-4BEC-9090-C3F3CBF25703} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} - {B43B546E-23F3-46E8-ACB7-D04F05CDA180} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} - {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} - {E4B71DC4-3E73-49C3-9B4E-CA13909F222D} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} - {C4939482-9447-47D1-B6AF-E9F8C6323841} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} - {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} - {600C4AE0-0585-4181-9CEC-2BB43430C713} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} - {823F80B6-E241-43F7-83BD-29FBB58A77F9} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} - {79E85459-EF54-44D6-9508-1E68B8238D00} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} - {9C3C685E-3D7D-4638-A031-24F71CF74B52} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} - {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3} - {18BE8F72-E528-4617-B1B1-07BD35337DFC} = {9C3C685E-3D7D-4638-A031-24F71CF74B52} - {01DC21DD-C6E2-4B21-864E-97D29448F777} = {9C3C685E-3D7D-4638-A031-24F71CF74B52} - {258F624E-98D7-4498-AE2E-F612D8ECA763} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} - {468E498C-59DB-4541-8D8A-0D89DE9083AB} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} - {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539} = {468E498C-59DB-4541-8D8A-0D89DE9083AB} - {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE} = {468E498C-59DB-4541-8D8A-0D89DE9083AB} - {0A3C36AB-2ACF-4175-A512-66B4C3DB9371} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6} - {475EEB95-ED27-4366-88EA-97C5000AC8E8} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371} - {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6} - {E7C689EB-5AD6-4E91-A007-6116EEA702FC} = {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} - {C042677F-973C-4672-AFA1-31B389962FE5} = {600C4AE0-0585-4181-9CEC-2BB43430C713} - {3F43514A-927E-4C62-B153-AFCAD7B1A7FC} = {600C4AE0-0585-4181-9CEC-2BB43430C713} - {36A6F881-1B40-438D-9B6D-80F01CE76D51} = {600C4AE0-0585-4181-9CEC-2BB43430C713} - {DA825F41-EE97-47B3-801E-C694A6C53AEC} = {600C4AE0-0585-4181-9CEC-2BB43430C713} - {071DD6EC-D00C-4513-82B6-3FE8438061E3} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} - {150EF356-E8BC-4922-91C2-362017479409} = {600C4AE0-0585-4181-9CEC-2BB43430C713} - {12D29DDC-A885-4CAA-908C-106D845B10C0} = {468E498C-59DB-4541-8D8A-0D89DE9083AB} - {DF47517F-9029-44DF-A29F-F2DE15041473} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} - {E224F8CF-F9F5-4E99-B405-758F3C02C47A} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} - {A11D79AE-F4C9-4595-9B73-0E0AB221B90D} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} - {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} - {1678743A-9095-4683-8DCD-5763F41924E2} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} - {7AC91435-7D10-4353-9064-598A6F8EAED6} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29509.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core", "src\core\Elsa.Core\Elsa.Core.csproj", "{300EE2D5-54C5-46F2-AD03-BB43589EA074}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{7165BB9E-F22C-40D2-B7B1-CA3EFA2529A0}" + ProjectSection(SolutionItems) = preProject + .dockerignore = .dockerignore + .editorconfig = .editorconfig + .gitignore = .gitignore + docker-compose.yaml = docker-compose.yaml + Dockerfile = Dockerfile + Nuget.Config = Nuget.Config + README.md = README.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Abstractions", "src\core\Elsa.Abstractions\Elsa.Abstractions.csproj", "{3130C574-557C-4DA2-933E-AED7A9EBE48A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{35F44BE9-13D0-417C-A01A-F0787BEE6DC3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Console", "src\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj", "{B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Http", "src\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj", "{1D63E1B4-2386-4BEC-9090-C3F3CBF25703}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "activities", "activities", "{B43B546E-23F3-46E8-ACB7-D04F05CDA180}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Email", "src\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj", "{D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Timers", "src\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj", "{E4B71DC4-3E73-49C3-9B4E-CA13909F222D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.MassTransit", "src\activities\Elsa.Activities.MassTransit\Elsa.Activities.MassTransit.csproj", "{C4939482-9447-47D1-B6AF-E9F8C6323841}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5E5E1E84-DDBC-40D6-B891-0D563A15A44A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "providers", "providers", "{600C4AE0-0585-4181-9CEC-2BB43430C713}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.UserTask", "src\activities\Elsa.Activities.UserTask\Elsa.Activities.UserTask.csproj", "{823F80B6-E241-43F7-83BD-29FBB58A77F9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Dropbox", "src\activities\Elsa.Activities.Dropbox\Elsa.Activities.Dropbox.csproj", "{79E85459-EF54-44D6-9508-1E68B8238D00}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripting", "scripting", "{9C3C685E-3D7D-4638-A031-24F71CF74B52}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa", "src\core\Elsa\Elsa.csproj", "{6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Scripting.JavaScript", "src\scripting\Elsa.Scripting.JavaScript\Elsa.Scripting.JavaScript.csproj", "{18BE8F72-E528-4617-B1B1-07BD35337DFC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Scripting.Liquid", "src\scripting\Elsa.Scripting.Liquid\Elsa.Scripting.Liquid.csproj", "{01DC21DD-C6E2-4B21-864E-97D29448F777}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Reflection", "src\activities\Elsa.Activities.Reflection\Elsa.Activities.Reflection.csproj", "{258F624E-98D7-4498-AE2E-F612D8ECA763}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "server", "server", "{468E498C-59DB-4541-8D8A-0D89DE9083AB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Core", "src\server\Elsa.Server.Core\Elsa.Server.Core.csproj", "{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Host", "src\server\Elsa.Server.Host\Elsa.Server.Host.csproj", "{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AB1AE008-6FD6-414C-8E88-D735F42E1FA6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core.UnitTests", "test\unit\Elsa.Core.UnitTests\Elsa.Core.UnitTests.csproj", "{475EEB95-ED27-4366-88EA-97C5000AC8E8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Testing.Shared", "test\shared\Elsa.Testing.Shared\Elsa.Testing.Shared.csproj", "{E7C689EB-5AD6-4E91-A007-6116EEA702FC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.DocumentDb", "src\providers\Elsa.Persistence.DocumentDb\Elsa.Persistence.DocumentDb.csproj", "{C042677F-973C-4672-AFA1-31B389962FE5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.EntityFrameworkCore", "src\providers\Elsa.Persistence.EntityFrameworkCore\Elsa.Persistence.EntityFrameworkCore.csproj", "{3F43514A-927E-4C62-B153-AFCAD7B1A7FC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.MongoDb", "src\providers\Elsa.Persistence.MongoDb\Elsa.Persistence.MongoDb.csproj", "{36A6F881-1B40-438D-9B6D-80F01CE76D51}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.YesSql", "src\providers\Elsa.Persistence.YesSql\Elsa.Persistence.YesSql.csproj", "{DA825F41-EE97-47B3-801E-C694A6C53AEC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Timers", "src\samples\Elsa.Samples.Timers\Elsa.Samples.Timers.csproj", "{071DD6EC-D00C-4513-82B6-3FE8438061E3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.SqlServer", "src\providers\Elsa.DistributedLocking.SqlServer\Elsa.DistributedLocking.SqlServer.csproj", "{150EF356-E8BC-4922-91C2-362017479409}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.GraphQL", "src\server\Elsa.Server.GraphQL\Elsa.Server.GraphQL.csproj", "{12D29DDC-A885-4CAA-908C-106D845B10C0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Serialization", "src\samples\Elsa.Samples.Serialization\Elsa.Samples.Serialization.csproj", "{DF47517F-9029-44DF-A29F-F2DE15041473}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.HelloWorldConsole", "src\samples\Elsa.Samples.HelloWorldConsole\Elsa.Samples.HelloWorldConsole.csproj", "{E224F8CF-F9F5-4E99-B405-758F3C02C47A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.HelloWorldHttp", "src\samples\Elsa.Samples.HelloWorldHttp\Elsa.Samples.HelloWorldHttp.csproj", "{A11D79AE-F4C9-4595-9B73-0E0AB221B90D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.CustomActivities", "src\samples\Elsa.Samples.CustomActivities\Elsa.Samples.CustomActivities.csproj", "{554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.TimesheetApproval", "src\samples\Elsa.Samples.TimesheetApproval\Elsa.Samples.TimesheetApproval.csproj", "{1678743A-9095-4683-8DCD-5763F41924E2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.WorkflowDefinition", "src\samples\Elsa.Samples.WorkflowDefinition\Elsa.Samples.WorkflowDefinition.csproj", "{7AC91435-7D10-4353-9064-598A6F8EAED6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.Redis", "src\providers\Elsa.DistributedLocking.Redis\Elsa.DistributedLocking.Redis.csproj", "{EBD49CCA-5400-4C36-B5DF-7B28190AA323}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.DistributedLock", "src\samples\Elsa.Samples.DistributedLock\Elsa.Samples.DistributedLock.csproj", "{4D162E3C-0962-43B9-B193-6E806249F81B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.DistributedLocking.AzureBlob", "src\providers\Elsa.DistributedLocking.AzureBlob\Elsa.DistributedLocking.AzureBlob.csproj", "{E20238CE-5C64-4F87-8753-3B4E1EC9A740}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {300EE2D5-54C5-46F2-AD03-BB43589EA074}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {300EE2D5-54C5-46F2-AD03-BB43589EA074}.Debug|Any CPU.Build.0 = Debug|Any CPU + {300EE2D5-54C5-46F2-AD03-BB43589EA074}.Release|Any CPU.ActiveCfg = Release|Any CPU + {300EE2D5-54C5-46F2-AD03-BB43589EA074}.Release|Any CPU.Build.0 = Release|Any CPU + {3130C574-557C-4DA2-933E-AED7A9EBE48A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3130C574-557C-4DA2-933E-AED7A9EBE48A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3130C574-557C-4DA2-933E-AED7A9EBE48A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3130C574-557C-4DA2-933E-AED7A9EBE48A}.Release|Any CPU.Build.0 = Release|Any CPU + {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F}.Release|Any CPU.Build.0 = Release|Any CPU + {1D63E1B4-2386-4BEC-9090-C3F3CBF25703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D63E1B4-2386-4BEC-9090-C3F3CBF25703}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D63E1B4-2386-4BEC-9090-C3F3CBF25703}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D63E1B4-2386-4BEC-9090-C3F3CBF25703}.Release|Any CPU.Build.0 = Release|Any CPU + {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}.Release|Any CPU.Build.0 = Release|Any CPU + {E4B71DC4-3E73-49C3-9B4E-CA13909F222D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4B71DC4-3E73-49C3-9B4E-CA13909F222D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4B71DC4-3E73-49C3-9B4E-CA13909F222D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4B71DC4-3E73-49C3-9B4E-CA13909F222D}.Release|Any CPU.Build.0 = Release|Any CPU + {C4939482-9447-47D1-B6AF-E9F8C6323841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4939482-9447-47D1-B6AF-E9F8C6323841}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4939482-9447-47D1-B6AF-E9F8C6323841}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4939482-9447-47D1-B6AF-E9F8C6323841}.Release|Any CPU.Build.0 = Release|Any CPU + {823F80B6-E241-43F7-83BD-29FBB58A77F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {823F80B6-E241-43F7-83BD-29FBB58A77F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {823F80B6-E241-43F7-83BD-29FBB58A77F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {823F80B6-E241-43F7-83BD-29FBB58A77F9}.Release|Any CPU.Build.0 = Release|Any CPU + {79E85459-EF54-44D6-9508-1E68B8238D00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79E85459-EF54-44D6-9508-1E68B8238D00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79E85459-EF54-44D6-9508-1E68B8238D00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79E85459-EF54-44D6-9508-1E68B8238D00}.Release|Any CPU.Build.0 = Release|Any CPU + {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Release|Any CPU.Build.0 = Release|Any CPU + {18BE8F72-E528-4617-B1B1-07BD35337DFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18BE8F72-E528-4617-B1B1-07BD35337DFC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18BE8F72-E528-4617-B1B1-07BD35337DFC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18BE8F72-E528-4617-B1B1-07BD35337DFC}.Release|Any CPU.Build.0 = Release|Any CPU + {01DC21DD-C6E2-4B21-864E-97D29448F777}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01DC21DD-C6E2-4B21-864E-97D29448F777}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01DC21DD-C6E2-4B21-864E-97D29448F777}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01DC21DD-C6E2-4B21-864E-97D29448F777}.Release|Any CPU.Build.0 = Release|Any CPU + {258F624E-98D7-4498-AE2E-F612D8ECA763}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {258F624E-98D7-4498-AE2E-F612D8ECA763}.Debug|Any CPU.Build.0 = Debug|Any CPU + {258F624E-98D7-4498-AE2E-F612D8ECA763}.Release|Any CPU.ActiveCfg = Release|Any CPU + {258F624E-98D7-4498-AE2E-F612D8ECA763}.Release|Any CPU.Build.0 = Release|Any CPU + {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.Build.0 = Release|Any CPU + {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.Build.0 = Release|Any CPU + {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.Build.0 = Release|Any CPU + {E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.Build.0 = Release|Any CPU + {C042677F-973C-4672-AFA1-31B389962FE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C042677F-973C-4672-AFA1-31B389962FE5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C042677F-973C-4672-AFA1-31B389962FE5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C042677F-973C-4672-AFA1-31B389962FE5}.Release|Any CPU.Build.0 = Release|Any CPU + {3F43514A-927E-4C62-B153-AFCAD7B1A7FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F43514A-927E-4C62-B153-AFCAD7B1A7FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F43514A-927E-4C62-B153-AFCAD7B1A7FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F43514A-927E-4C62-B153-AFCAD7B1A7FC}.Release|Any CPU.Build.0 = Release|Any CPU + {36A6F881-1B40-438D-9B6D-80F01CE76D51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {36A6F881-1B40-438D-9B6D-80F01CE76D51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {36A6F881-1B40-438D-9B6D-80F01CE76D51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {36A6F881-1B40-438D-9B6D-80F01CE76D51}.Release|Any CPU.Build.0 = Release|Any CPU + {DA825F41-EE97-47B3-801E-C694A6C53AEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA825F41-EE97-47B3-801E-C694A6C53AEC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA825F41-EE97-47B3-801E-C694A6C53AEC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA825F41-EE97-47B3-801E-C694A6C53AEC}.Release|Any CPU.Build.0 = Release|Any CPU + {071DD6EC-D00C-4513-82B6-3FE8438061E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {071DD6EC-D00C-4513-82B6-3FE8438061E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {071DD6EC-D00C-4513-82B6-3FE8438061E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {071DD6EC-D00C-4513-82B6-3FE8438061E3}.Release|Any CPU.Build.0 = Release|Any CPU + {150EF356-E8BC-4922-91C2-362017479409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {150EF356-E8BC-4922-91C2-362017479409}.Debug|Any CPU.Build.0 = Debug|Any CPU + {150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.ActiveCfg = Release|Any CPU + {150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.Build.0 = Release|Any CPU + {12D29DDC-A885-4CAA-908C-106D845B10C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12D29DDC-A885-4CAA-908C-106D845B10C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12D29DDC-A885-4CAA-908C-106D845B10C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12D29DDC-A885-4CAA-908C-106D845B10C0}.Release|Any CPU.Build.0 = Release|Any CPU + {DF47517F-9029-44DF-A29F-F2DE15041473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF47517F-9029-44DF-A29F-F2DE15041473}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF47517F-9029-44DF-A29F-F2DE15041473}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF47517F-9029-44DF-A29F-F2DE15041473}.Release|Any CPU.Build.0 = Release|Any CPU + {E224F8CF-F9F5-4E99-B405-758F3C02C47A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E224F8CF-F9F5-4E99-B405-758F3C02C47A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E224F8CF-F9F5-4E99-B405-758F3C02C47A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E224F8CF-F9F5-4E99-B405-758F3C02C47A}.Release|Any CPU.Build.0 = Release|Any CPU + {A11D79AE-F4C9-4595-9B73-0E0AB221B90D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A11D79AE-F4C9-4595-9B73-0E0AB221B90D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A11D79AE-F4C9-4595-9B73-0E0AB221B90D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A11D79AE-F4C9-4595-9B73-0E0AB221B90D}.Release|Any CPU.Build.0 = Release|Any CPU + {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F}.Release|Any CPU.Build.0 = Release|Any CPU + {1678743A-9095-4683-8DCD-5763F41924E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1678743A-9095-4683-8DCD-5763F41924E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1678743A-9095-4683-8DCD-5763F41924E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1678743A-9095-4683-8DCD-5763F41924E2}.Release|Any CPU.Build.0 = Release|Any CPU + {7AC91435-7D10-4353-9064-598A6F8EAED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AC91435-7D10-4353-9064-598A6F8EAED6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AC91435-7D10-4353-9064-598A6F8EAED6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AC91435-7D10-4353-9064-598A6F8EAED6}.Release|Any CPU.Build.0 = Release|Any CPU + {EBD49CCA-5400-4C36-B5DF-7B28190AA323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBD49CCA-5400-4C36-B5DF-7B28190AA323}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBD49CCA-5400-4C36-B5DF-7B28190AA323}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBD49CCA-5400-4C36-B5DF-7B28190AA323}.Release|Any CPU.Build.0 = Release|Any CPU + {4D162E3C-0962-43B9-B193-6E806249F81B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D162E3C-0962-43B9-B193-6E806249F81B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D162E3C-0962-43B9-B193-6E806249F81B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D162E3C-0962-43B9-B193-6E806249F81B}.Release|Any CPU.Build.0 = Release|Any CPU + {E20238CE-5C64-4F87-8753-3B4E1EC9A740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E20238CE-5C64-4F87-8753-3B4E1EC9A740}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E20238CE-5C64-4F87-8753-3B4E1EC9A740}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E20238CE-5C64-4F87-8753-3B4E1EC9A740}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {300EE2D5-54C5-46F2-AD03-BB43589EA074} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3} + {3130C574-557C-4DA2-933E-AED7A9EBE48A} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3} + {35F44BE9-13D0-417C-A01A-F0787BEE6DC3} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} + {B98B80CB-D3A3-437C-A61C-ED82C8C77B2F} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} + {1D63E1B4-2386-4BEC-9090-C3F3CBF25703} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} + {B43B546E-23F3-46E8-ACB7-D04F05CDA180} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} + {D20FCB88-9DCA-49EA-9CC2-5B94DD935D30} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} + {E4B71DC4-3E73-49C3-9B4E-CA13909F222D} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} + {C4939482-9447-47D1-B6AF-E9F8C6323841} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} + {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} + {600C4AE0-0585-4181-9CEC-2BB43430C713} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} + {823F80B6-E241-43F7-83BD-29FBB58A77F9} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} + {79E85459-EF54-44D6-9508-1E68B8238D00} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} + {9C3C685E-3D7D-4638-A031-24F71CF74B52} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} + {6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3} + {18BE8F72-E528-4617-B1B1-07BD35337DFC} = {9C3C685E-3D7D-4638-A031-24F71CF74B52} + {01DC21DD-C6E2-4B21-864E-97D29448F777} = {9C3C685E-3D7D-4638-A031-24F71CF74B52} + {258F624E-98D7-4498-AE2E-F612D8ECA763} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} + {468E498C-59DB-4541-8D8A-0D89DE9083AB} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} + {D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539} = {468E498C-59DB-4541-8D8A-0D89DE9083AB} + {FC54EDBA-71FB-4A87-8FD5-54759DF77CCE} = {468E498C-59DB-4541-8D8A-0D89DE9083AB} + {0A3C36AB-2ACF-4175-A512-66B4C3DB9371} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6} + {475EEB95-ED27-4366-88EA-97C5000AC8E8} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371} + {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6} + {E7C689EB-5AD6-4E91-A007-6116EEA702FC} = {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} + {C042677F-973C-4672-AFA1-31B389962FE5} = {600C4AE0-0585-4181-9CEC-2BB43430C713} + {3F43514A-927E-4C62-B153-AFCAD7B1A7FC} = {600C4AE0-0585-4181-9CEC-2BB43430C713} + {36A6F881-1B40-438D-9B6D-80F01CE76D51} = {600C4AE0-0585-4181-9CEC-2BB43430C713} + {DA825F41-EE97-47B3-801E-C694A6C53AEC} = {600C4AE0-0585-4181-9CEC-2BB43430C713} + {071DD6EC-D00C-4513-82B6-3FE8438061E3} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} + {150EF356-E8BC-4922-91C2-362017479409} = {600C4AE0-0585-4181-9CEC-2BB43430C713} + {12D29DDC-A885-4CAA-908C-106D845B10C0} = {468E498C-59DB-4541-8D8A-0D89DE9083AB} + {DF47517F-9029-44DF-A29F-F2DE15041473} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} + {E224F8CF-F9F5-4E99-B405-758F3C02C47A} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} + {A11D79AE-F4C9-4595-9B73-0E0AB221B90D} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} + {554C21D7-10BE-48E6-B0EF-9FCA43B32A0F} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} + {1678743A-9095-4683-8DCD-5763F41924E2} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} + {7AC91435-7D10-4353-9064-598A6F8EAED6} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} + {EBD49CCA-5400-4C36-B5DF-7B28190AA323} = {600C4AE0-0585-4181-9CEC-2BB43430C713} + {4D162E3C-0962-43B9-B193-6E806249F81B} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} + {E20238CE-5C64-4F87-8753-3B4E1EC9A740} = {600C4AE0-0585-4181-9CEC-2BB43430C713} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158} + EndGlobalSection +EndGlobal diff --git a/src/activities/Elsa.Activities.Timers/HostedServices/TimersHostedService.cs b/src/activities/Elsa.Activities.Timers/HostedServices/TimersHostedService.cs index 016b3e77b..2c4fd8c72 100644 --- a/src/activities/Elsa.Activities.Timers/HostedServices/TimersHostedService.cs +++ b/src/activities/Elsa.Activities.Timers/HostedServices/TimersHostedService.cs @@ -2,6 +2,7 @@ using System; using System.Threading; using System.Threading.Tasks; using Elsa.Activities.Timers.Options; +using Elsa.DistributedLock; using Elsa.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -20,7 +21,7 @@ namespace Elsa.Activities.Timers.HostedServices public TimersHostedService( IServiceProvider serviceProvider, IDistributedLockProvider distributedLockProvider, - IOptions options, + IOptions options, ILogger logger) { this.serviceProvider = serviceProvider; @@ -28,12 +29,11 @@ namespace Elsa.Activities.Timers.HostedServices this.options = options; this.logger = logger; } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { - if (await distributedLockProvider.AcquireLockAsync(GetType().Name, stoppingToken)) + if (await distributedLockProvider.AcquireLockAsync(GetType().Name, stoppingToken).ConfigureAwait(false)) { try { diff --git a/src/core/Elsa.Abstractions/Services/IDistributedLockProvider.cs b/src/core/Elsa.Abstractions/DistributedLock/IDistributedLockProvider.cs similarity index 95% rename from src/core/Elsa.Abstractions/Services/IDistributedLockProvider.cs rename to src/core/Elsa.Abstractions/DistributedLock/IDistributedLockProvider.cs index dd88ba774..37920dde0 100644 --- a/src/core/Elsa.Abstractions/Services/IDistributedLockProvider.cs +++ b/src/core/Elsa.Abstractions/DistributedLock/IDistributedLockProvider.cs @@ -1,7 +1,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Elsa.Services +namespace Elsa.DistributedLock { /// /// Provides functionality to acquire and release locks which are distributed across all instances in a web farm. @@ -12,6 +12,7 @@ namespace Elsa.Services public interface IDistributedLockProvider { Task AcquireLockAsync(string name, CancellationToken cancellationToken = default); + Task ReleaseLockAsync(string name, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/src/core/Elsa.Core/Services/DefaultLockProvider.cs b/src/core/Elsa.Core/DistributedLock/DefaultLockProvider.cs similarity index 96% rename from src/core/Elsa.Core/Services/DefaultLockProvider.cs rename to src/core/Elsa.Core/DistributedLock/DefaultLockProvider.cs index 6ca20d012..1609d0c7e 100644 --- a/src/core/Elsa.Core/Services/DefaultLockProvider.cs +++ b/src/core/Elsa.Core/DistributedLock/DefaultLockProvider.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace Elsa.Services +namespace Elsa.DistributedLock { /// /// An in-memory, single-node lock provider. Used by default, and suitable only in single-instance hosting environments. @@ -29,7 +29,7 @@ namespace Elsa.Services { lock (locks) locks.Remove(name); - + return Task.CompletedTask; } } diff --git a/src/core/Elsa.Core/ElsaOptions.cs b/src/core/Elsa.Core/ElsaOptions.cs index 387136221..85d9df898 100644 --- a/src/core/Elsa.Core/ElsaOptions.cs +++ b/src/core/Elsa.Core/ElsaOptions.cs @@ -1,5 +1,6 @@ -using System; +using System; using Elsa.Caching; +using Elsa.DistributedLock; using Elsa.Persistence; using Elsa.Persistence.Memory; using Elsa.Services; @@ -61,8 +62,8 @@ namespace Elsa ServiceBusConfigurer = configure; return this; } - - public ElsaOptions ConfigureServiceBus(Func configure) => + + public ElsaOptions ConfigureServiceBus(Func configure) => ConfigureServiceBus((bus, _) => configure(bus)); private static RebusConfigurer ConfigureInMemoryServiceBus(RebusConfigurer rebus, IServiceProvider serviceProvider) diff --git a/src/core/Elsa.Core/StartupTasks/ResumeRunningWorkflowsTask.cs b/src/core/Elsa.Core/StartupTasks/ResumeRunningWorkflowsTask.cs index 40d24b94f..595e6ec83 100644 --- a/src/core/Elsa.Core/StartupTasks/ResumeRunningWorkflowsTask.cs +++ b/src/core/Elsa.Core/StartupTasks/ResumeRunningWorkflowsTask.cs @@ -1,5 +1,6 @@ using System.Threading; using System.Threading.Tasks; +using Elsa.DistributedLock; using Elsa.Models; using Elsa.Persistence; using Elsa.Runtime; @@ -18,7 +19,7 @@ namespace Elsa.StartupTasks private readonly IDistributedLockProvider distributedLockProvider; public ResumeRunningWorkflowsTask( - IWorkflowInstanceStore workflowInstanceStore, + IWorkflowInstanceStore workflowInstanceStore, IWorkflowScheduler workflowScheduler, IDistributedLockProvider distributedLockProvider) { @@ -26,12 +27,12 @@ namespace Elsa.StartupTasks this.workflowScheduler = workflowScheduler; this.distributedLockProvider = distributedLockProvider; } - + public async Task ExecuteAsync(CancellationToken cancellationToken = default) { if (!await distributedLockProvider.AcquireLockAsync(GetType().Name, cancellationToken)) return; - + var instances = await workflowInstanceStore.ListByStatusAsync(WorkflowStatus.Running, cancellationToken); foreach (var instance in instances) diff --git a/src/providers/Elsa.DistributedLocking.AzureBlob/AzureBlobLockProvider.cs b/src/providers/Elsa.DistributedLocking.AzureBlob/AzureBlobLockProvider.cs new file mode 100644 index 000000000..37afb3499 --- /dev/null +++ b/src/providers/Elsa.DistributedLocking.AzureBlob/AzureBlobLockProvider.cs @@ -0,0 +1,204 @@ +using Elsa.DistributedLock; +using Microsoft.Azure.Storage; +using Microsoft.Azure.Storage.Blob; +using Microsoft.Azure.Storage.RetryPolicies; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.DistributedLocking.AzureBlob +{ + // See also: + // The lock duration can be 15 to 60 seconds, or can be infinite, Reference: https://docs.microsoft.com/en-us/rest/api/storageservices/lease-blob + + public class AzureBlobLockProvider : IDistributedLockProvider + { + private const string Prefix = "elsa"; + private const string ContainerName = "elsa-lock-container"; + private const int MaxLeaseTime = 60; + private const int MinLeaseTime = 15; + private readonly AutoResetEvent _leaseSemaphore = new AutoResetEvent(true); + private static readonly object syncRoot = new Object(); + private readonly List _lockedBlobs = new List(); + private readonly string _connectionString; + private TimeSpan _leaseTime; + private readonly ILogger _logger; + private CloudBlobContainer _cloudBlobContainer; + private readonly TimeSpan _renewInterval; + private Timer _renewTimer; + + public AzureBlobLockProvider(string connectionString, TimeSpan leaseTime, TimeSpan renewInterval, + ILogger logger) + { + _logger = logger; + _connectionString = connectionString; + if (leaseTime >= TimeSpan.FromSeconds(MaxLeaseTime) || leaseTime <= TimeSpan.FromSeconds(MinLeaseTime)) + { + _logger.LogInformation("Leasetime must be between 15 Seconds and 60 seconds, Found {leaseTime.TotalSeconds} seconds. Setting default value of 60 seconds", leaseTime.TotalSeconds); + _leaseTime = TimeSpan.FromSeconds(MaxLeaseTime); + } + else + { + _leaseTime = leaseTime; + } + if (renewInterval > leaseTime) + { + _logger.LogError("Renew Interval can not be greater than LeaseTime {leaseTime.TotalSeconds}.", leaseTime.TotalSeconds); + throw new InvalidDataException($"Renew Interval can not be greater than LeaseTime {leaseTime.TotalSeconds}."); + } + _renewInterval = renewInterval; + } + public Task AcquireLockAsync(string name, CancellationToken cancellationToken = default) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + return CreateLockAsync(name, cancellationToken); + + } + + private async Task CreateLockAsync(string name, CancellationToken cancellationToken=default) + { + var resourceName = $"{Prefix}:{name}"; + var blob = CloudBlobContainer.GetBlockBlobReference(resourceName); + + if (!await blob.ExistsAsync(cancellationToken).ConfigureAwait(false)) + await blob.UploadTextAsync(string.Empty,cancellationToken).ConfigureAwait(false); + + _renewTimer = new Timer(RenewLeases, null, _renewInterval, _renewInterval); + _logger.LogInformation("Lock provider will try to acquire lock for {resourceName}",resourceName); + + if (_leaseSemaphore.WaitOne()) + { + try + { + var leaseId = await blob.AcquireLeaseAsync(_leaseTime, null, cancellationToken).ConfigureAwait(false); + _lockedBlobs.Add(new LockedBlob { Blob = blob, LeaseId = leaseId, Identifier = resourceName }); + + _logger.LogInformation("Lock provider acquired lock for {resourceName}",resourceName); + return true; + } + catch (Exception ex) + { + _logger.LogWarning("Failed to acquire lock for {resourceName}. Reason > {ex}",resourceName,ex); + return false; + } + finally + { + _leaseSemaphore.Set(); + } + } + return false; + } + + public Task ReleaseLockAsync(string name, CancellationToken cancellationToken = default) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + return ReleaseLeaseAsync(name, cancellationToken); + } + private async Task ReleaseLeaseAsync(string name, CancellationToken cancellationToken =default) + { + var resourceName = $"{Prefix}:{name}"; + _logger.LogInformation("Lock provider will try to release lock for {resourceName}",resourceName); + + if (_leaseSemaphore.WaitOne()) + { + try + { + var lockedBlob = _lockedBlobs.FirstOrDefault(x => x.Identifier == resourceName); + + if (lockedBlob != null) + { + try + { + await lockedBlob.Blob + .ReleaseLeaseAsync(AccessCondition.GenerateLeaseCondition(lockedBlob.LeaseId),cancellationToken) + .ConfigureAwait(false); + + _logger.LogInformation("Lock provider released lock for {resourceName}",resourceName); + } + catch (Exception ex) + { + _logger.LogWarning("Failed to release lock for {resourceName}. Reason > {ex}",resourceName,ex); + } + _lockedBlobs.Remove(lockedBlob); + } + } + finally + { + _leaseSemaphore.Set(); + _renewTimer?.Dispose(); + } + } + } + + private CloudBlobContainer CloudBlobContainer + { + get + { + if (_cloudBlobContainer == null) + { + lock (syncRoot) + { + if (_cloudBlobContainer == null) + { + var blobClient = CloudStorageAccount.Parse(_connectionString) + .CreateCloudBlobClient(); + blobClient.DefaultRequestOptions.RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(2.0), 3); + _cloudBlobContainer = blobClient.GetContainerReference(ContainerName); + if (!_cloudBlobContainer.Exists()) + { + _cloudBlobContainer.CreateIfNotExists(BlobContainerPublicAccessType.Off, (BlobRequestOptions)null, (OperationContext)null); + } + } + } + } + + return _cloudBlobContainer; + } + } + private async void RenewLeases(object state) + { + _logger.LogDebug("Renew active leases"); + if (_leaseSemaphore.WaitOne()) + { + + try + { + foreach (var lockedBlobs in _lockedBlobs) + await RenewLock(lockedBlobs).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Error while renewing leases"); + } + finally + { + _leaseSemaphore.Set(); + } + } + } + private async Task RenewLock(LockedBlob lockedBlob) + { + try + { + await lockedBlob.Blob.RenewLeaseAsync(AccessCondition.GenerateLeaseCondition(lockedBlob.LeaseId)); + _logger.LogInformation("Renewed active leases for {lockedBlob.Identifier}", lockedBlob.Identifier); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Error while renewing lock"); + } + } + } +} diff --git a/src/providers/Elsa.DistributedLocking.AzureBlob/Elsa.DistributedLocking.AzureBlob.csproj b/src/providers/Elsa.DistributedLocking.AzureBlob/Elsa.DistributedLocking.AzureBlob.csproj new file mode 100644 index 000000000..ad4a38723 --- /dev/null +++ b/src/providers/Elsa.DistributedLocking.AzureBlob/Elsa.DistributedLocking.AzureBlob.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/src/providers/Elsa.DistributedLocking.AzureBlob/ElsaOptionsExtensions.cs b/src/providers/Elsa.DistributedLocking.AzureBlob/ElsaOptionsExtensions.cs new file mode 100644 index 000000000..f6f2eeea0 --- /dev/null +++ b/src/providers/Elsa.DistributedLocking.AzureBlob/ElsaOptionsExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System; + +namespace Elsa.DistributedLocking.AzureBlob +{ + public static class ElsaOptionsExtensions + { + public static ElsaOptions UseAzureBlobLockProvider(this ElsaOptions options, string connectionString, TimeSpan? leaseTime=null, TimeSpan? renewInterval=null) + { + options + .UseDistributedLockProvider(sp => new AzureBlobLockProvider(connectionString, + leaseTime ?? TimeSpan.FromSeconds(60), + renewInterval ?? TimeSpan.FromSeconds(45), + sp.GetRequiredService>())); + return options; + } + } +} diff --git a/src/providers/Elsa.DistributedLocking.AzureBlob/LockedBlob.cs b/src/providers/Elsa.DistributedLocking.AzureBlob/LockedBlob.cs new file mode 100644 index 000000000..009c891e7 --- /dev/null +++ b/src/providers/Elsa.DistributedLocking.AzureBlob/LockedBlob.cs @@ -0,0 +1,22 @@ +using Elsa.DistributedLock; +using Microsoft.Azure.Storage; +using Microsoft.Azure.Storage.Blob; +using Microsoft.Azure.Storage.RetryPolicies; +using Microsoft.Extensions.Logging; +using NodaTime; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.DistributedLocking.AzureBlob +{ + internal class LockedBlob + { + public string Identifier { get; set; } + public string LeaseId { get; set; } + public CloudBlockBlob Blob { get; set; } + } +} diff --git a/src/providers/Elsa.DistributedLocking.Redis/Elsa.DistributedLocking.Redis.csproj b/src/providers/Elsa.DistributedLocking.Redis/Elsa.DistributedLocking.Redis.csproj new file mode 100644 index 000000000..2be1dd9fc --- /dev/null +++ b/src/providers/Elsa.DistributedLocking.Redis/Elsa.DistributedLocking.Redis.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/src/providers/Elsa.DistributedLocking.Redis/ElsaOptionsExtensions.cs b/src/providers/Elsa.DistributedLocking.Redis/ElsaOptionsExtensions.cs new file mode 100644 index 000000000..bf4268a0e --- /dev/null +++ b/src/providers/Elsa.DistributedLocking.Redis/ElsaOptionsExtensions.cs @@ -0,0 +1,45 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RedLockNet; +using RedLockNet.SERedis; +using RedLockNet.SERedis.Configuration; +using StackExchange.Redis; +using System; +using System.Collections.Generic; + +namespace Elsa.DistributedLocking.Redis +{ + public static class ElsaOptionsExtensions + { + public static ElsaOptions UseRedisLockProvider(this ElsaOptions options, string connectionString, TimeSpan? lockTimeout = null) + { + options.UseStackExchangeConnectionMultiplexer(connectionString) + .UseRedLockFactory() + .UseDistributedLockProvider(sp => new RedisLockProvider(sp.GetRequiredService(), + lockTimeout ?? TimeSpan.FromMinutes(1), + sp.GetRequiredService>())); + return options; + } + + private static ElsaOptions UseStackExchangeConnectionMultiplexer(this ElsaOptions options, string connectionString) + { + if (string.IsNullOrWhiteSpace(connectionString)) + { + throw new ArgumentNullException(nameof(connectionString)); + } + options.Services.AddSingleton(ConnectionMultiplexer.Connect(connectionString)); + + return options; + } + private static ElsaOptions UseRedLockFactory(this ElsaOptions options) + { + options.Services.AddSingleton(sp => + RedLockFactory.Create(new List + { + new RedLockMultiplexer(sp.GetRequiredService()) + })); + + return options; + } + } +} \ No newline at end of file diff --git a/src/providers/Elsa.DistributedLocking.Redis/RedisLockProvider.cs b/src/providers/Elsa.DistributedLocking.Redis/RedisLockProvider.cs new file mode 100644 index 000000000..dbb41ffad --- /dev/null +++ b/src/providers/Elsa.DistributedLocking.Redis/RedisLockProvider.cs @@ -0,0 +1,99 @@ +using Elsa.DistributedLock; +using Microsoft.Extensions.Logging; +using RedLockNet; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.DistributedLocking.Redis +{ + public class RedisLockProvider : IDistributedLockProvider + { + private const string Prefix = "elsa"; + private readonly ILogger _logger; + private readonly TimeSpan _lockTimeout; + private readonly IDistributedLockFactory _distributedLockFactory; + private readonly List RedLockInstance = new List(); + + public RedisLockProvider(IDistributedLockFactory distributedLockFactory, TimeSpan lockTimeout, ILogger logger) + { + _logger = logger; + _distributedLockFactory = distributedLockFactory; + _lockTimeout = lockTimeout; + } + public Task AcquireLockAsync(string name, CancellationToken cancellationToken = default) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + return CreateLockAsync(name, cancellationToken); + } + private async Task CreateLockAsync(string name, CancellationToken cancellationToken = default) + { + var resourceName = $"{Prefix}:{name}"; + _logger.LogInformation($"Lock provider will try to acquire lock for {resourceName}"); + try + { + var redLock = await _distributedLockFactory.CreateLockAsync(resourceName, _lockTimeout, + TimeSpan.FromSeconds(1), + TimeSpan.FromMilliseconds(10), + cancellationToken) + .ConfigureAwait(false); + + if (redLock.IsAcquired) + { + + lock (RedLockInstance) + { + RedLockInstance.Add(redLock); + } + _logger.LogInformation($"Lock provider acquired lock for {resourceName}"); + + return true; + } + return false; + } + catch (Exception ex) + { + _logger.LogWarning($"Failed to acquire lock for {resourceName}. Reason > {ex}"); + return false; + } + } + + public Task ReleaseLockAsync(string name, CancellationToken cancellationToken = default) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + var resourceName = $"{Prefix}:{name}"; + + _logger.LogInformation($"Lock provider will try to release lock for {resourceName}"); + try + { + lock (RedLockInstance) + { + foreach (var redLock in RedLockInstance) + { + if (redLock.Resource == $"{Prefix}:{name}") + { + redLock.Dispose(); + RedLockInstance.Remove(redLock); + _logger.LogInformation($"Lock provider released lock for {resourceName}"); + break; + } + } + } + } + catch (Exception ex) + { + _logger.LogWarning($"Failed to release lock for {resourceName}. Reason > {ex}"); + } + return Task.CompletedTask; + } + + } +} \ No newline at end of file diff --git a/src/providers/Elsa.DistributedLocking.SqlServer/SqlLockProvider.cs b/src/providers/Elsa.DistributedLocking.SqlServer/SqlLockProvider.cs index 0fe248cf7..3c956af5e 100644 --- a/src/providers/Elsa.DistributedLocking.SqlServer/SqlLockProvider.cs +++ b/src/providers/Elsa.DistributedLocking.SqlServer/SqlLockProvider.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Threading; using System.Threading.Tasks; -using Elsa.Services; +using Elsa.DistributedLock; using Microsoft.Extensions.Logging; namespace Elsa.DistributedLocking.SqlServer @@ -61,12 +61,15 @@ namespace Elsa.DistributedLocking.SqlServer case -1: logger.LogDebug($"The lock request timed out for {name}"); break; + case -2: logger.LogDebug($"The lock request was canceled for {name}"); break; + case -3: logger.LogDebug($"The lock request was chosen as a deadlock victim for {name}"); break; + case -999: logger.LogError($"Lock provider error for {name}"); break; @@ -99,14 +102,13 @@ namespace Elsa.DistributedLocking.SqlServer { if (!mutex.WaitOne()) return; - + try { - if (!locks.ContainsKey(name)) return; - - var connection = locks[name]; + + var connection = locks[name]; if (connection == null) return; @@ -118,7 +120,7 @@ namespace Elsa.DistributedLocking.SqlServer command.CommandType = CommandType.StoredProcedure; command.Parameters.AddWithValue("@Resource", $"{Prefix}:{name}"); command.Parameters.AddWithValue("@LockOwner", $"Session"); - + var returnParameter = command.Parameters.Add("RetVal", SqlDbType.Int); returnParameter.Direction = ParameterDirection.ReturnValue; diff --git a/src/samples/Elsa.Samples.DistributedLock/Elsa.Samples.DistributedLock.csproj b/src/samples/Elsa.Samples.DistributedLock/Elsa.Samples.DistributedLock.csproj new file mode 100644 index 000000000..02eb763cb --- /dev/null +++ b/src/samples/Elsa.Samples.DistributedLock/Elsa.Samples.DistributedLock.csproj @@ -0,0 +1,21 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + + + + diff --git a/src/samples/Elsa.Samples.DistributedLock/Program.cs b/src/samples/Elsa.Samples.DistributedLock/Program.cs new file mode 100644 index 000000000..11075e576 --- /dev/null +++ b/src/samples/Elsa.Samples.DistributedLock/Program.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using NodaTime; +using System.Threading.Tasks; +using Elsa.DistributedLocking.Redis; +using Elsa.DistributedLocking.AzureBlob; +using System; + +namespace Elsa.Samples.DistributedLock +{ + internal static class Program + { + private static async Task Main() + { + await CreateHostBuilder().UseConsoleLifetime().Build().RunAsync(); + } + + public static IHostBuilder CreateHostBuilder() => + Host.CreateDefaultBuilder() + .ConfigureServices((hostContext, services) => + { + services + .AddElsa(options => + options + .UseMongoDbWorkflowStores("Elsa_Samples_Timers", "mongodb://localhost") + .UseAzureBlobLockProvider("UseDevelopmentStorage=true")) + //.UseRedisLockProvider("redis-16642.xx.redislabs.com:16642,password=xxxxxx")) + + .AddConsoleActivities() + .AddSingleton(Console.In) + .AddTimerActivities(options => + options.Configure(timer => timer.SweepInterval = Duration.FromSeconds(5))) + .AddWorkflow(); + }); + } +} \ No newline at end of file diff --git a/src/samples/Elsa.Samples.DistributedLock/RecurringWorkflow.cs b/src/samples/Elsa.Samples.DistributedLock/RecurringWorkflow.cs new file mode 100644 index 000000000..6615b720f --- /dev/null +++ b/src/samples/Elsa.Samples.DistributedLock/RecurringWorkflow.cs @@ -0,0 +1,22 @@ +using Elsa.Activities.Console; +using Elsa.Activities.MassTransit; +using Elsa.Builders; +using Elsa.Expressions; +using Elsa.Models; +using NodaTime; +using System; + +namespace Elsa.Samples.DistributedLock +{ + public class RecurringWorkflow : IWorkflow + { + public void Build(IWorkflowBuilder builder) + { + builder + .WithPersistenceBehavior(WorkflowPersistenceBehavior.ActivityExecuted) + .TimerEvent(Duration.FromSeconds(1)) + .WriteLine(new CodeExpression("Hello World")) + .WriteLine(() => $"Timer event at {DateTime.Now}"); + } + } +} \ No newline at end of file