From 4eaa282e5eb443232d0ec09116cf308de06d6f5c Mon Sep 17 00:00:00 2001 From: Behzad Alizadeh Date: Mon, 25 Aug 2025 23:59:58 +0330 Subject: [PATCH] remove workflows 's dedicated appsettings.json and change registration of it --- .../Program.cs | 8 +- .../appsettings.json | 281 +-------- .../appsettings.workflow.Development.json | 9 - .../appsettings.workflow.json | 285 --------- .../Config/DependencyInjection.cs | 583 ++---------------- 5 files changed, 43 insertions(+), 1123 deletions(-) delete mode 100644 src/apps/Caspian.WorkflowFramework.Sample/appsettings.workflow.Development.json delete mode 100644 src/apps/Caspian.WorkflowFramework.Sample/appsettings.workflow.json diff --git a/src/apps/Caspian.WorkflowFramework.Sample/Program.cs b/src/apps/Caspian.WorkflowFramework.Sample/Program.cs index 16d0e68..95701f0 100644 --- a/src/apps/Caspian.WorkflowFramework.Sample/Program.cs +++ b/src/apps/Caspian.WorkflowFramework.Sample/Program.cs @@ -1,4 +1,4 @@ -using Caspian.WorkflowFramework; +using Caspian.WorkflowFramework; using Caspian.WorkflowFramework.Sample; using Microsoft.OpenApi.Models; using San.MongoLogger; @@ -29,9 +29,8 @@ builder.Services.AddSwaggerGen(c => }); //Workflow -//var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); -var t = $"appsettings.workflow.{builder.Environment.EnvironmentName}.json"; -builder.AddWorkflowFramework($"appsettings.workflow.json"); +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); +builder.AddWorkflowFramework(connectionString); builder.Services.AddMongoLogger(builder.Configuration); @@ -61,6 +60,7 @@ app.MapControllers(); //Workflow app.UseWorkflowFramework(); + // Redirect to Swagger URL app.Use(async (context, next) => { diff --git a/src/apps/Caspian.WorkflowFramework.Sample/appsettings.json b/src/apps/Caspian.WorkflowFramework.Sample/appsettings.json index eab431b..c53f2ba 100644 --- a/src/apps/Caspian.WorkflowFramework.Sample/appsettings.json +++ b/src/apps/Caspian.WorkflowFramework.Sample/appsettings.json @@ -38,285 +38,6 @@ "reloadConfigOnChange": true }, "ConnectionStrings": { - "DefaultConnection": "Data Source=.;Initial Catalog=WorkflowFrameworkTest;User ID=sa;Password=123456;Integrated Security=false;TrustServerCertificate=True;", - //"Sqlite": "", //"Data Source=App_Data/elsa.sqlite.db;Cache=Shared;", - ////"SqlServer": "Server=localhost,1433;Initial Catalog=Elsa;User=sa;Password=!Elsa2025@;Encrypt=false;PersistSecurityInfo=false", - //"SqlServer": "Data Source=.;Initial Catalog=WorkflowFrameworkTest;User ID=sa;Password=123456;Integrated Security=false;TrustServerCertificate=True;", - //"MySql": "", //"Server=localhost;Database=elsa;Uid=admin;Pwd=password;", - //"PostgreSql": "", //"Server=localhost;Username=elsa;Database=elsa;Port=5432;Password=elsa;SSLMode=Prefer;MaxPoolSize=2000;Timeout=60", - //"Citus": "", //"Server=localhost;Username=citus;Database=citus;Port=9700;Password=citus;SSLMode=Prefer;MaxPoolSize=2000;Timeout=60", - //"YugabyteDb": "", //"Host=localhost;Port=5433;Database=elsa;Username=yugabyte;Password=yugabyte;Pooling=true", - //"Oracle": "", //"Data Source=(DESCRIPTION = (ADDRESS_LIST = (FAILOVER =ON) (LOAD_BALANCE = OFF) (ADDRESS = (PROTOCOL =TCP)(HOST=localhost)(PORT=1521))) (CONNECT_DATA = (SID= FREE) ));User Id=ELSA;Password=elsa;", - //"CockroachDb": "", //"Host=localhost;Port=26257;Database=elsa;SslMode=Disable;Username=root;IncludeErrorDetail=true", - //"MongoDb": "", //"mongodb://localhost:27017/elsa-workflows", - //"AzureServiceBus": "", - //"RabbitMq": "", //"amqp://guest:guest@localhost:5672", - //"Redis": "" //"localhost:6379,abortConnect=false" + "DefaultConnection": "Data Source=.;Initial Catalog=WfDb;User ID=sa;Password=123456;Integrated Security=false;TrustServerCertificate=True;" } - //"DatabaseProvider": "SqlServer", //"Sqlite", - //"Multitenancy": { - // "Tenants": [ - // { - // "Id": null, - // "Name": "Default", - // "Configuration": { - // "Http": { - // "Prefix": "", - // "Host": "localhost:5001" - // }, - // "ConnectionStrings": { - // "Sqlite": "Data Source=App_Data/elsa.sqlite.db;Cache=Shared;" - // } - // } - // }, - // { - // "Id": "tenant-1", - // "Name": "Tenant 1", - // "Configuration": { - // "Http": { - // "Prefix": "tenant-1", - // "Host": "localhost:5001" - // }, - // "ConnectionStrings": { - // "Sqlite": "Data Source=App_Data/elsa.sqlite.db;Cache=Shared;" - // } - // } - // } - // ] - //}, - //"Smtp": { - // "Host": "localhost", - // "Port": 2525, - // "DefaultSender": "noreply@crmservices.com" - //}, - //"Http": { - // "BaseUrl": "https://localhost:5001", - // "BasePath": "/workflows", - // "ApiRoutePrefix": "elsa/api", - // "AvailableContentTypes": [ - // "application/json", - // "application/xml", - // "text/plain", - // "text/html" - // ] - //}, - //"Identity": { - // "Tokens": { - // "SigningKey": "sufficiently-large-secret-signing-key", - // "AccessTokenLifetime": "1:00:00:00", - // "RefreshTokenLifetime": "7:00:00:00" - // }, - // "Roles": [ - // { - // "Id": "admin", - // "Name": "Administrator", - // "Permissions": [ - // "*" - // ], - // "TenantId": "default" - // } - // ], - // "Users": [ - // { - // "Id": "a2323f46-42db-4e15-af8b-94238717d817", - // "Name": "admin", - // //"HashedPassword": "TfKzh9RLix6FPcCNeHLkGrysFu3bYxqzGqduNdi8v1U=", - // //"HashedPasswordSalt": "JEy9kBlhHCNsencitRHlGxmErmSgY+FVyMJulCH27Ds=", - // "HashedPassword": "p90gXKnVpt5Q2VZ4KkeOaM5GZN3bqjczoznWbnFMrvo=", - // "HashedPasswordSalt": "QmVzbWVsbGFoQHJSYWhtYW5AcnJhaDFt", - // "Roles": [ - // "admin" - // ], - // "TenantId": "" - // }, - // { - // "Id": "b0cd0e506e713a9d", - // "Name": "alice", - // "Roles": [ - // "admin" - // ], - // "HashedPassword": "8B0fFK/f/kk9GkVtzXfRJ2Y6cNyYVvLTfKouWcAcuPg=", - // "HashedPasswordSalt": "xlNWvEng8fRvo0McyJopbRJ2MJ9NIYV/4IY5dOZeiiw=", - // "TenantId": "tenant-2" - // }, - // { - // "Id": "789d5056cb3bb8e9", - // "Name": "bob", - // "Roles": [ - // "admin" - // ], - // "HashedPassword": "GMHHvUw7RfIIBq+GAWZ/AlHR50TbgONYfGQ92Xge0EI=", - // "HashedPasswordSalt": "V4uHKg1PFBc1bsngCQoptibOu14faj9obSn5B23h1wE=", - // "TenantId": "tenant-1" - // } - // ], - // "Applications": [ - // { - // "Id": "d57030226341448daff5a2935aba2d3f", - // "Name": "Postman", - // "Roles": [ - // "admin" - // ], - // "ClientId": "HXr0Vzdm9KCZbwsJ", - // "ClientSecret": "a<~QGGHTEA%u4;CU&'Wga5ED:_&Gd1C)", - // "HashedApiKey": "Z5ClHs3mbzx8Pnw3+PxbMq8A/Y+VKMCCDTGYtax8JFM=", - // "HashedApiKeySalt": "kBisa1X8FwBfN2zmyGMFRgIVVBleghhQAJ4WGyTkaD0=", - // "HashedClientSecret": "jEv58d0SVbGQ3nBZM0lkzHghG4Y+lMKW80wipz+9vHk=", - // "HashedClientSecretSalt": "xRKy14Ok1/tU3kLf/8V1fcbLIegy9vcM90Peu2tzohU=", - // "TenantId": "default" - // } - // ] - //}, - //"Environments": { - // "Environments": [ - // { - // "Name": "Local", - // "ServerUrl": "https://localhost:5001/elsa/api" - // }, - // { - // "Name": "Staging", - // "ServerUrl": "https://staging.acme.com/elsa/api" - // }, - // { - // "Name": "Production", - // "ServerUrl": "https://production.acme.com/elsa/api" - // } - // ] - //}, - //"AppRole": "Default", - //"Runtime": { - // "DistributedLocking": { - // "Provider": "File", - // "LockAcquisitionTimeout": "00:00:10" - // }, - // "DistributedLockProvider": "File", - // "WorkflowDispatcher": { - // "Channels": [ - // { - // "Name": "Low" - // }, - // { - // "Name": "Medium" - // }, - // { - // "Name": "High" - // } - // ] - // } - //}, - //"Scripting": { - // "Python": { - // "PythonDllPath": "", - // "Scripts": [ - // "def greet(name): return f'Hello {name}!'", - // "def say_hello_world(): return greet('World')" - // ] - // } - //}, - //"AzureServiceBus": { - // "Queues": [ - // { - // "Name": "queue1" - // }, - // { - // "Name": "queue2" - // } - // ], - // "Topics": [ - // { - // "Name": "topic1", - // "Subscriptions": [ - // { - // "Name": "subscription1" - // }, - // { - // "Name": "subscription2" - // } - // ] - // } - // ] - //}, - //"Kafka": { - // "Topics": [ - // { - // "Id": "topic-1", - // "Name": "topic-1" - // }, - // { - // "Id": "topic-2", - // "Name": "topic-2" - // } - // ], - // "SchemaRegistries": [ - // { - // "Id": "schema-registry-1", - // "Name": "Schema Registry 1", - // "Config": { - // "Url": "http://localhost:8081" - // } - // } - // ], - // "Producers": [ - // { - // "Id": "producer-1", - // "Name": "Producer 1", - // "FactoryType": "Elsa.Kafka.Factories.GenericProducerFactory`2[[System.String, System.Private.CoreLib], [Elsa.Server.Web.Messages.OrderReceived, Elsa.Server.Web]], Elsa.Kafka", - // "Config": { - // "BootstrapServers": "localhost:9092" - // }, - // "SchemaRegistryId": "schema-registry-1" - // } - // ], - // "Consumers": [ - // { - // "Id": "consumer-1", - // "Name": "Consumer 1", - // "FactoryType": "Elsa.Kafka.Factories.GenericConsumerFactory`2[[System.String, System.Private.CoreLib], [Elsa.Server.Web.Messages.OrderReceived, Elsa.Server.Web]], Elsa.Kafka", - // "Config": { - // "BootstrapServers": "localhost:9092", - // "GroupId": "group-1", - // "AutoOffsetReset": "earliest", - // "EnableAutoCommit": "true" - // }, - // "SchemaRegistryId": "schema-registry-1" - // } - // ] - //}, - //"Secrets": { - // "Management": { - // "SweepInterval": "04:00:00" - // } - //}, - //"Webhooks": { - // "Sinks": [ - // { - // "Id": "1", - // "Name": "Run Task", - // "Filters": [ - // { - // "EventType": "Elsa.RunTask" - // } - // ], - // "Url": "https://localhost:6001/webhooks/run-task" - // } - // ] - //}, - //"Resilience": { - // "Strategies": [ - // { - // "$type": "HttpResilienceStrategy", - // "Id": "1", - // "DisplayName": "Retry 3 times, exponential", - // "MaxRetryAttempts": 3, - // "BackoffType": "Exponential" - // }, - // { - // "$type": "HttpResilienceStrategy", - // "Id": "2", - // "DisplayName": "Retry 10 times, linear", - // "MaxRetryAttempts": 10, - // "BackoffType": "Linear" - // } - // ] - //} } diff --git a/src/apps/Caspian.WorkflowFramework.Sample/appsettings.workflow.Development.json b/src/apps/Caspian.WorkflowFramework.Sample/appsettings.workflow.Development.json deleted file mode 100644 index 84dfb83..0000000 --- a/src/apps/Caspian.WorkflowFramework.Sample/appsettings.workflow.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - //"Microsoft.EntityFrameworkCore.Database.Command": "Warning" // Disable SQL command logging - } - } -} diff --git a/src/apps/Caspian.WorkflowFramework.Sample/appsettings.workflow.json b/src/apps/Caspian.WorkflowFramework.Sample/appsettings.workflow.json deleted file mode 100644 index 5ab381e..0000000 --- a/src/apps/Caspian.WorkflowFramework.Sample/appsettings.workflow.json +++ /dev/null @@ -1,285 +0,0 @@ -{ - "HostBuilder": { - "reloadConfigOnChange": true - }, - "ConnectionStrings": { - //"Sqlite": "", //"Data Source=App_Data/elsa.sqlite.db;Cache=Shared;", - "SqlServer": "Data Source=.;Initial Catalog=WorkflowDb_3-5-0;User ID=sa;Password=123456;Integrated Security=false;TrustServerCertificate=True;" - //"MySql": "", //"Server=localhost;Database=elsa;Uid=admin;Pwd=password;", - //"PostgreSql": "", //"Server=localhost;Username=elsa;Database=elsa;Port=5432;Password=elsa;SSLMode=Prefer;MaxPoolSize=2000;Timeout=60", - //"Citus": "", //"Server=localhost;Username=citus;Database=citus;Port=9700;Password=citus;SSLMode=Prefer;MaxPoolSize=2000;Timeout=60", - //"YugabyteDb": "", //"Host=localhost;Port=5433;Database=elsa;Username=yugabyte;Password=yugabyte;Pooling=true", - //"Oracle": "", //"Data Source=(DESCRIPTION = (ADDRESS_LIST = (FAILOVER =ON) (LOAD_BALANCE = OFF) (ADDRESS = (PROTOCOL =TCP)(HOST=localhost)(PORT=1521))) (CONNECT_DATA = (SID= FREE) ));User Id=ELSA;Password=elsa;", - //"CockroachDb": "", //"Host=localhost;Port=26257;Database=elsa;SslMode=Disable;Username=root;IncludeErrorDetail=true", - //"MongoDb": "", //"mongodb://localhost:27017/elsa-workflows", - //"AzureServiceBus": "", - //"RabbitMq": "", //"amqp://guest:guest@localhost:5672", - //"Redis": "" //"localhost:6379,abortConnect=false" - }, - "DatabaseProvider": "SqlServer", //"Sqlite", - "Multitenancy": { - "Tenants": [ - { - "Id": null, - "Name": "Default", - "Configuration": { - "Http": { - "Prefix": "", - "Host": "localhost:5001" - }, - "ConnectionStrings": { - "Sqlite": "Data Source=App_Data/elsa.sqlite.db;Cache=Shared;" - } - } - }, - { - "Id": "tenant-1", - "Name": "Tenant 1", - "Configuration": { - "Http": { - "Prefix": "tenant-1", - "Host": "localhost:5001" - }, - "ConnectionStrings": { - "Sqlite": "Data Source=App_Data/elsa.sqlite.db;Cache=Shared;" - } - } - } - ] - }, - "Smtp": { - "Host": "localhost", - "Port": 2525, - "DefaultSender": "noreply@crmservices.com" - }, - "Http": { - "BaseUrl": "https://localhost:5001", - "BasePath": "/workflows", - "ApiRoutePrefix": "elsa/api", - "AvailableContentTypes": [ - "application/json", - "application/xml", - "text/plain", - "text/html" - ] - }, - "Identity": { - "Tokens": { - "SigningKey": "sufficiently-large-secret-signing-key", - "AccessTokenLifetime": "1:00:00:00", - "RefreshTokenLifetime": "7:00:00:00" - }, - "Roles": [ - { - "Id": "admin", - "Name": "Administrator", - "Permissions": [ - "*" - ], - "TenantId": "default" - } - ], - "Users": [ - { - "Id": "a2323f46-42db-4e15-af8b-94238717d817", - "Name": "admin", - //"HashedPassword": "TfKzh9RLix6FPcCNeHLkGrysFu3bYxqzGqduNdi8v1U=", - //"HashedPasswordSalt": "JEy9kBlhHCNsencitRHlGxmErmSgY+FVyMJulCH27Ds=", - "HashedPassword": "p90gXKnVpt5Q2VZ4KkeOaM5GZN3bqjczoznWbnFMrvo=", - "HashedPasswordSalt": "QmVzbWVsbGFoQHJSYWhtYW5AcnJhaDFt", - "Roles": [ - "admin" - ], - "TenantId": "" - }, - { - "Id": "b0cd0e506e713a9d", - "Name": "alice", - "Roles": [ - "admin" - ], - "HashedPassword": "8B0fFK/f/kk9GkVtzXfRJ2Y6cNyYVvLTfKouWcAcuPg=", - "HashedPasswordSalt": "xlNWvEng8fRvo0McyJopbRJ2MJ9NIYV/4IY5dOZeiiw=", - "TenantId": "tenant-2" - }, - { - "Id": "789d5056cb3bb8e9", - "Name": "bob", - "Roles": [ - "admin" - ], - "HashedPassword": "GMHHvUw7RfIIBq+GAWZ/AlHR50TbgONYfGQ92Xge0EI=", - "HashedPasswordSalt": "V4uHKg1PFBc1bsngCQoptibOu14faj9obSn5B23h1wE=", - "TenantId": "tenant-1" - } - ], - "Applications": [ - { - "Id": "d57030226341448daff5a2935aba2d3f", - "Name": "Postman", - "Roles": [ - "admin" - ], - "ClientId": "HXr0Vzdm9KCZbwsJ", - "ClientSecret": "a<~QGGHTEA%u4;CU&'Wga5ED:_&Gd1C)", - "HashedApiKey": "Z5ClHs3mbzx8Pnw3+PxbMq8A/Y+VKMCCDTGYtax8JFM=", - "HashedApiKeySalt": "kBisa1X8FwBfN2zmyGMFRgIVVBleghhQAJ4WGyTkaD0=", - "HashedClientSecret": "jEv58d0SVbGQ3nBZM0lkzHghG4Y+lMKW80wipz+9vHk=", - "HashedClientSecretSalt": "xRKy14Ok1/tU3kLf/8V1fcbLIegy9vcM90Peu2tzohU=", - "TenantId": "default" - } - ] - }, - "Environments": { - "Environments": [ - { - "Name": "Local", - "ServerUrl": "https://localhost:5001/elsa/api" - }, - { - "Name": "Staging", - "ServerUrl": "https://staging.acme.com/elsa/api" - }, - { - "Name": "Production", - "ServerUrl": "https://production.acme.com/elsa/api" - } - ] - }, - "AppRole": "Default", - "Runtime": { - "DistributedLocking": { - "Provider": "File", - "LockAcquisitionTimeout": "00:00:10" - }, - "DistributedLockProvider": "File", - "WorkflowDispatcher": { - "Channels": [ - { - "Name": "Low" - }, - { - "Name": "Medium" - }, - { - "Name": "High" - } - ] - } - }, - "Scripting": { - "Python": { - "PythonDllPath": "", - "Scripts": [ - "def greet(name): return f'Hello {name}!'", - "def say_hello_world(): return greet('World')" - ] - } - }, - "AzureServiceBus": { - "Queues": [ - { - "Name": "queue1" - }, - { - "Name": "queue2" - } - ], - "Topics": [ - { - "Name": "topic1", - "Subscriptions": [ - { - "Name": "subscription1" - }, - { - "Name": "subscription2" - } - ] - } - ] - }, - "Kafka": { - "Topics": [ - { - "Id": "topic-1", - "Name": "topic-1" - }, - { - "Id": "topic-2", - "Name": "topic-2" - } - ], - "SchemaRegistries": [ - { - "Id": "schema-registry-1", - "Name": "Schema Registry 1", - "Config": { - "Url": "http://localhost:8081" - } - } - ], - "Producers": [ - { - "Id": "producer-1", - "Name": "Producer 1", - "FactoryType": "Elsa.Kafka.Factories.GenericProducerFactory`2[[System.String, System.Private.CoreLib], [Elsa.Server.Web.Messages.OrderReceived, Elsa.Server.Web]], Elsa.Kafka", - "Config": { - "BootstrapServers": "localhost:9092" - }, - "SchemaRegistryId": "schema-registry-1" - } - ], - "Consumers": [ - { - "Id": "consumer-1", - "Name": "Consumer 1", - "FactoryType": "Elsa.Kafka.Factories.GenericConsumerFactory`2[[System.String, System.Private.CoreLib], [Elsa.Server.Web.Messages.OrderReceived, Elsa.Server.Web]], Elsa.Kafka", - "Config": { - "BootstrapServers": "localhost:9092", - "GroupId": "group-1", - "AutoOffsetReset": "earliest", - "EnableAutoCommit": "true" - }, - "SchemaRegistryId": "schema-registry-1" - } - ] - }, - "Secrets": { - "Management": { - "SweepInterval": "04:00:00" - } - }, - "Webhooks": { - "Sinks": [ - { - "Id": "1", - "Name": "Run Task", - "Filters": [ - { - "EventType": "Elsa.RunTask" - } - ], - "Url": "https://localhost:6001/webhooks/run-task" - } - ] - }, - "Resilience": { - "Strategies": [ - { - "$type": "HttpResilienceStrategy", - "Id": "1", - "DisplayName": "Retry 3 times, exponential", - "MaxRetryAttempts": 3, - "BackoffType": "Exponential" - }, - { - "$type": "HttpResilienceStrategy", - "Id": "2", - "DisplayName": "Retry 10 times, linear", - "MaxRetryAttempts": 10, - "BackoffType": "Linear" - } - ] - } -} diff --git a/src/apps/Caspian.WorkflowFramework/Config/DependencyInjection.cs b/src/apps/Caspian.WorkflowFramework/Config/DependencyInjection.cs index 1c0dbb4..68830f5 100644 --- a/src/apps/Caspian.WorkflowFramework/Config/DependencyInjection.cs +++ b/src/apps/Caspian.WorkflowFramework/Config/DependencyInjection.cs @@ -1,206 +1,60 @@ -using System.IO; -using System.Text.Encodings.Web; -using Caspian.WorkflowFramework.Contracts; +using Caspian.WorkflowFramework.Contracts; using Caspian.WorkflowFramework.Services; -using Elsa.Alterations.Extensions; -using Elsa.Alterations.MassTransit.Extensions; using Elsa.Caching.Options; -using Elsa.Common.Codecs; -using Elsa.Common.DistributedHosting.DistributedLocks; using Elsa.Common.RecurringTasks; using Elsa.Common.Serialization; -using Elsa.Dapper.Extensions; -using Elsa.Dapper.Services; -using Elsa.DropIns.Extensions; using Elsa.EntityFrameworkCore.Extensions; using Elsa.EntityFrameworkCore.Modules.Alterations; using Elsa.EntityFrameworkCore.Modules.Identity; using Elsa.EntityFrameworkCore.Modules.Management; using Elsa.EntityFrameworkCore.Modules.Runtime; using Elsa.EntityFrameworkCore.Modules.Tenants; -using Elsa.Expressions.Helpers; using Elsa.Extensions; -using Elsa.Features.Services; -using Elsa.Identity.Multitenancy; -using Elsa.Kafka; using Elsa.Kafka.Factories; -using Elsa.MassTransit.Extensions; -using Elsa.MongoDb.Extensions; -using Elsa.MongoDb.Modules.Alterations; -using Elsa.MongoDb.Modules.Identity; -using Elsa.MongoDb.Modules.Management; -using Elsa.MongoDb.Modules.Runtime; -using Elsa.MongoDb.Modules.Tenants; using Elsa.OpenTelemetry.Middleware; -using Elsa.Retention.Extensions; -using Elsa.Retention.Models; -using Elsa.Secrets.Extensions; using Elsa.Secrets.Management.Tasks; using Elsa.Secrets.Persistence; using Elsa.Server.Web; -using Elsa.Server.Web.Extensions; -using Elsa.Server.Web.Filters; using Elsa.Server.Web.Messages; -using Elsa.Sql.Extensions; -using Elsa.Sql.MySql; -using Elsa.Sql.PostgreSql; -using Elsa.Sql.Sqlite; -using Elsa.Sql.SqlServer; -using Elsa.Tenants.AspNetCore; -using Elsa.Tenants.Extensions; using Elsa.Workflows; -using Elsa.Workflows.Api; -using Elsa.Workflows.CommitStates.Strategies; using Elsa.Workflows.IncidentStrategies; using Elsa.Workflows.LogPersistence; using Elsa.Workflows.Management; -using Elsa.Workflows.Management.Stores; using Elsa.Workflows.Options; using Elsa.Workflows.Runtime.Distributed.Extensions; using Elsa.Workflows.Runtime.Options; -using Elsa.Workflows.Runtime.Stores; using Elsa.Workflows.Runtime.Tasks; -using Hangfire; -using Hangfire.MemoryStorage; -using Hangfire.PostgreSql; -using Hangfire.PostgreSql.Factories; -using Hangfire.SqlServer; -using Hangfire.Storage.SQLite; -using JetBrains.Annotations; -using Medallion.Threading.FileSystem; -using Medallion.Threading.Postgres; -using Medallion.Threading.Redis; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using OpenTelemetry.Metrics; -using OpenTelemetry.Resources; -using OpenTelemetry.Trace; -using Proto.Cluster.Kubernetes; -using Proto.Persistence.Sqlite; -using Proto.Persistence.SqlServer; -using Proto.Remote; -using Proto.Remote.GrpcNet; using San.MongoLogger; using San.MongoLogger.Models; -using StackExchange.Redis; namespace Caspian.WorkflowFramework; public static class DependencyInjection { - const PersistenceProvider persistenceProvider = PersistenceProvider.EntityFrameworkCore; - const WorkflowRuntime workflowRuntime = WorkflowRuntime.Distributed; - const DistributedCachingTransport distributedCachingTransport = DistributedCachingTransport.Memory; - const MassTransitBroker massTransitBroker = MassTransitBroker.Memory; - const bool useDbContextPooling = false; - const bool useHangfire = false; - const bool useQuartz = true; - const bool useMassTransit = false; - const bool useZipCompression = false; - const bool runEFCoreMigrations = true; - const bool useMemoryStores = false; - const bool useCaching = true; - const bool useKafka = false; - const bool useReadOnlyMode = false; - const bool useSignalR = false; // Disabled until Elsa Studio sends authenticated requests. - const bool useMultitenancy = false; - const bool useTenantsFromConfiguration = true; - const bool useSecrets = false; - const bool disableVariableWrappers = false; - const bool disableVariableCopying = false; - const bool useManualOtelInstrumentation = false; - - public static void AddWorkflowFramework(this IHostApplicationBuilder builder, string appsettingName) + public static void AddWorkflowFramework(this IHostApplicationBuilder builder, string sqlServerConnectionString) { - var configuration = new ConfigurationBuilder() - .AddJsonFile(appsettingName, optional: false, reloadOnChange: true) - .Build(); - //var configuration = builder.Configuration; - var heartbeatSection = configuration.GetSection("Heartbeat"); - var identitySection = configuration.GetSection("Identity"); - var identityTokenSection = identitySection.GetSection("Tokens"); - var sqliteConnectionString = configuration.GetConnectionString("Sqlite")!; - var sqlServerConnectionString = configuration.GetConnectionString("SqlServer")!; - var postgresConnectionString = configuration.GetConnectionString("PostgreSql")!; - var citusConnectionString = configuration.GetConnectionString("Citus")!; - var yugabyteDbConnectionString = configuration.GetConnectionString("YugabyteDb")!; - var oracleConnectionString = configuration.GetConnectionString("Oracle")!; - var mySqlConnectionString = configuration.GetConnectionString("MySql")!; - var cockroachDbConnectionString = configuration.GetConnectionString("CockroachDb")!; - var mongoDbConnectionString = configuration.GetConnectionString("MongoDb")!; - var azureServiceBusConnectionString = configuration.GetConnectionString("AzureServiceBus")!; - var rabbitMqConnectionString = configuration.GetConnectionString("RabbitMq")!; - var redisConnectionString = configuration.GetConnectionString("Redis")!; - var distributedLockProviderName = configuration.GetSection("Runtime:DistributedLocking")["Provider"]; - var appRole = Enum.Parse(configuration["AppRole"]! ?? "Default"); - var sqlDatabaseProvider = Enum.Parse(configuration["DatabaseProvider"] ?? "SqlServer"); - const PersistenceProvider persistenceProvider = PersistenceProvider.EntityFrameworkCore; + //var configuration = new ConfigurationBuilder() + // .AddJsonFile(appsettingName, optional: false, reloadOnChange: true) + // .Build(); + //var sqlServerConnectionString = configuration.GetConnectionString("SqlServer")!; + + var sqlDatabaseProvider = Enum.Parse("SqlServer"); const bool useDbContextPooling = false; - const bool useHangfire = false; - const bool useQuartz = false;//true; - const bool useMassTransit = false; - const bool useZipCompression = false; const bool runEFCoreMigrations = true; - const bool useMemoryStores = false; const bool useCaching = true; - const bool useKafka = false; const bool useReadOnlyMode = false; - const bool useSignalR = false; // Disabled until Elsa Studio sends authenticated requests. const WorkflowRuntime workflowRuntime = WorkflowRuntime.Distributed; - const DistributedCachingTransport distributedCachingTransport = DistributedCachingTransport.Memory; - const MassTransitBroker massTransitBroker = MassTransitBroker.Memory; - const bool useMultitenancy = false; - const bool useTenantsFromConfiguration = false;// true; - const bool useSecrets = false; const bool disableVariableWrappers = false; const bool disableVariableCopying = false; - const bool useManualOtelInstrumentation = false; // Optionally create type aliases for easier configuration. TypeAliasRegistry.RegisterAlias("OrderReceivedProducerFactory", typeof(GenericProducerFactory)); TypeAliasRegistry.RegisterAlias("OrderReceivedConsumerFactory", typeof(GenericConsumerFactory)); - if (useManualOtelInstrumentation) - { - builder.Services - .AddOpenTelemetry() - .ConfigureResource(resource => resource.AddService("elsa-workflows", serviceVersion: "3.5.0").AddTelemetrySdk()) - .WithTracing(tracing => - { - tracing - .AddSource("*") - .SetSampler(new AlwaysOnSampler()) - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddSqlClientInstrumentation() - .AddConsoleExporter() - .AddOtlpExporter() - ; - }) - .WithMetrics(metrics => - { - metrics - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddConsoleExporter() - .AddOtlpExporter() - ; - }); - - // Enable OpenTelemetry Logging (optional) - builder.Logging.AddOpenTelemetry(options => - { - options.IncludeFormattedMessage = true; - options.IncludeScopes = true; - options.ParseStateValues = true; - }); - } - // Add Elsa services. builder.Services.AddScoped(); @@ -216,7 +70,8 @@ public static class DependencyInjection workflows.UseCommitStrategies(strategies => { strategies.AddStandardStrategies(); - strategies.Add("Every 10 seconds", new PeriodicWorkflowStrategy(TimeSpan.FromSeconds(10))); + //می خوایم سریع انجام شه + //strategies.Add("Every 10 seconds", new PeriodicWorkflowStrategy(TimeSpan.FromSeconds(10))); }); }) .UseWorkflowManagement(management => @@ -226,15 +81,6 @@ public static class DependencyInjection ef.UseSqlServer(sqlServerConnectionString); }); - if (useZipCompression) - management.SetCompressionAlgorithm(nameof(Zstd)); - - if (useMemoryStores) - management.UseWorkflowInstances(feature => feature.WorkflowInstanceStore = sp => sp.GetRequiredService()); - - if (useMassTransit) - management.UseMassTransitDispatcher(); - if (useCaching) management.UseCache(); @@ -243,87 +89,31 @@ public static class DependencyInjection management.AddVariableTypeAndAlias("Application"); }) .UseWorkflowRuntime(runtime => - { - runtime.UseEntityFrameworkCore(ef => - { - ef.UseContextPooling = useDbContextPooling; - - //ef.UseSqlServer(sqlServerConnectionString, new ElsaDbContextOptions); - var migrationsAssembly = typeof(Elsa.EntityFrameworkCore.SqlServer.IdentityDbContextFactory).Assembly; - var connectionString = sqlServerConnectionString; - ef.DbContextOptionsBuilder = (_, db) => db.UseElsaSqlServer(migrationsAssembly, connectionString, null, configure => configure.CommandTimeout(60000)); - - ef.RunMigrations = runEFCoreMigrations; - }); - - if (workflowRuntime == WorkflowRuntime.Distributed) - { - runtime.UseDistributedRuntime(); - } - - if (workflowRuntime == WorkflowRuntime.ProtoActor) - { - runtime.UseProtoActor(); - } - - if (useMassTransit) - runtime.UseMassTransitDispatcher(); - - runtime.WorkflowDispatcherOptions = options => configuration.GetSection("Runtime:WorkflowDispatcher").Bind(options); - - if (useMemoryStores) - { - runtime.ActivityExecutionLogStore = sp => sp.GetRequiredService(); - runtime.WorkflowExecutionLogStore = sp => sp.GetRequiredService(); - } - - if (useCaching) - runtime.UseCache(); - - runtime.DistributedLockingOptions = options => configuration.GetSection("Runtime:DistributedLocking").Bind(options); - - runtime.DistributedLockProvider = _ => - { - switch (distributedLockProviderName) - { - case "Postgres": - return new PostgresDistributedSynchronizationProvider(postgresConnectionString, options => - { - options.KeepaliveCadence(TimeSpan.FromMinutes(5)); - options.UseMultiplexing(); - }); - case "Redis": - { - var connectionMultiplexer = ConnectionMultiplexer.Connect(redisConnectionString); - var database = connectionMultiplexer.GetDatabase(); - return new RedisDistributedSynchronizationProvider(database); - } - case "File": - return new FileDistributedSynchronizationProvider(new(Path.Combine(Directory.GetCurrentDirectory(), "App_Data", "locks"))); - case "Noop": - default: - return new NoopDistributedSynchronizationProvider(); - } - }; - }) - .UseEnvironments(environments => environments.EnvironmentsOptions = options => configuration.GetSection("Environments").Bind(options)) - .UseScheduling(scheduling => { - if (useHangfire) - scheduling.UseHangfireScheduler(); + runtime.UseEntityFrameworkCore(ef => + { + ef.UseContextPooling = useDbContextPooling; - if (useQuartz) - scheduling.UseQuartzScheduler(); - }) - .UseWorkflowsApi(api => - { - api.AddFastEndpointsAssembly(); + var migrationsAssembly = typeof(Elsa.EntityFrameworkCore.SqlServer.IdentityDbContextFactory).Assembly; + var connectionString = sqlServerConnectionString; + ef.DbContextOptionsBuilder = (_, db) => db.UseElsaSqlServer(migrationsAssembly, connectionString, null, configure => configure.CommandTimeout(60000)); + + ef.RunMigrations = runEFCoreMigrations; + }); + + if (workflowRuntime == WorkflowRuntime.Distributed) + { + runtime.UseDistributedRuntime(); + } + + if (useCaching) + runtime.UseCache(); }) .UseCSharp(options => { options.DisableWrappers = disableVariableWrappers; - options.AppendScript("string Greet(string name) => $\"Hello {name}!\";"); - options.AppendScript("string SayHelloWorld() => Greet(\"World\");"); + //options.AppendScript("string Greet(string name) => $\"Hello {name}!\";"); + //options.AppendScript("string SayHelloWorld() => Greet(\"World\");"); }) .UseJavaScript(options => { @@ -331,286 +121,17 @@ public static class DependencyInjection options.DisableWrappers = disableVariableWrappers; options.DisableVariableCopying = disableVariableCopying; options.RegisterType(); - options.ConfigureEngine(engine => - { - engine.Execute("function greet(name) { return `Hello ${name}!`; }"); - engine.Execute("function sayHelloWorld() { return greet('World'); }"); - }); + //options.ConfigureEngine(engine => + //{ + // engine.Execute("function greet(name) { return `Hello ${name}!`; }"); + // engine.Execute("function sayHelloWorld() { return greet('World'); }"); + //}); }) - .UsePython(python => - { - python.PythonOptions += options => - { - // Make sure to configure the path to the python DLL. E.g. /opt/homebrew/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/bin/python3.11 - // alternatively, you can set the PYTHONNET_PYDLL environment variable. - configuration.GetSection("Scripting:Python").Bind(options); - - options.AddScript(sb => - { - sb.AppendLine("def greet():"); - sb.AppendLine(" return \"Hello, welcome to Python!\""); - }); - }; - }) - .UseLiquid(liquid => liquid.FluidOptions = options => options.Encoder = HtmlEncoder.Default) - .UseHttp(http => - { - http.ConfigureHttpOptions = options => configuration.GetSection("Http").Bind(options); - - if (useCaching) - http.UseCache(); - }) - .UseSql(options => - { - options.Clients = client => - { - client.Register("MySql"); - client.Register("PostgreSql"); - client.Register("Sqlite"); - client.Register("Sql Server"); - }; - }) - .UseEmail(email => email.ConfigureOptions = options => configuration.GetSection("Smtp").Bind(options)) - .UseAlterations(alterations => - { - if (persistenceProvider == PersistenceProvider.MongoDb) - { - alterations.UseMongoDb(); - } - else if (persistenceProvider == PersistenceProvider.Dapper) - { - // TODO: alterations.UseDapper(); - } - else - { - alterations.UseEntityFrameworkCore(ef => - { - ef.UseContextPooling = useDbContextPooling; - ef.UseSqlServer(sqlServerConnectionString); - ef.RunMigrations = runEFCoreMigrations; - }); - } - - if (useMassTransit) - { - alterations.UseMassTransitDispatcher(); - } - }) - .UseOpenTelemetry(otel => otel.UseNewRootActivityForRemoteParent = true) .UseWorkflowContexts(); - - if (useQuartz) - { - elsa.UseQuartz(quartz => - { - if (sqlDatabaseProvider == SqlDatabaseProvider.Sqlite) - quartz.UseSqlite(sqliteConnectionString); - else if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql) - quartz.UsePostgreSql(postgresConnectionString); - }); - } - - if (useSignalR) - { - elsa.UseRealTimeWorkflows(); - } - - if (useMassTransit) - { - elsa.UseMassTransit(massTransit => - { - massTransit.DisableConsumers = appRole == ApplicationRole.Api; - massTransit.AddMessageType(); - - if (massTransitBroker == MassTransitBroker.AzureServiceBus) - { - massTransit.UseAzureServiceBus(azureServiceBusConnectionString, serviceBusFeature => serviceBusFeature.ConfigureTransportBus = (context, bus) => - { - bus.PrefetchCount = 50; - bus.LockDuration = TimeSpan.FromMinutes(5); - bus.MaxConcurrentCalls = 32; - bus.MaxDeliveryCount = 8; - // etc. - }); - } - - if (massTransitBroker == MassTransitBroker.RabbitMq) - { - massTransit.UseRabbitMq(rabbitMqConnectionString, rabbit => rabbit.ConfigureTransportBus = (context, bus) => - { - bus.PrefetchCount = 50; - bus.Durable = true; - bus.AutoDelete = false; - bus.ConcurrentMessageLimit = 32; - // etc. - }); - } - }); - } - - if (distributedCachingTransport != DistributedCachingTransport.None) - { - elsa.UseDistributedCache(distributedCaching => - { - if (distributedCachingTransport == DistributedCachingTransport.MassTransit) distributedCaching.UseMassTransit(); - if (distributedCachingTransport == DistributedCachingTransport.ProtoActor) distributedCaching.UseProtoActor(); - }); - } - - if (distributedCachingTransport == DistributedCachingTransport.ProtoActor || workflowRuntime == WorkflowRuntime.ProtoActor) - { - elsa.UseProtoActor(proto => - { - proto - .EnableMetrics() - .EnableTracing(); - - proto.PersistenceProvider = _ => - { - if (sqlDatabaseProvider == SqlDatabaseProvider.SqlServer) - return new SqlServerProvider(sqlServerConnectionString, true, "", "proto_actor"); - return new SqliteProvider(new(sqliteConnectionString)); - }; - - if (configuration["KUBERNETES_SERVICE_HOST"] != null) - { - var kubernetesConfig = new KubernetesProviderConfig(); - var clusterProvider = new KubernetesProvider(kubernetesConfig); - - var remoteConfig = GrpcNetRemoteConfig - .BindToAllInterfaces(advertisedHost: configuration["ProtoActor:AdvertisedHost"]) // Environment variable to be provided by Kubernetes using pod.status.podIP. - .WithLogLevelForDeserializationErrors(LogLevel.Critical) - .WithRemoteDiagnostics(true); - - proto.CreateClusterProvider = _ => clusterProvider; - proto.ConfigureRemoteConfig = _ => remoteConfig; - } - }); - } - - if (useKafka) - { - elsa.UseKafka(kafka => - { - kafka.ConfigureOptions(options => configuration.GetSection("Kafka").Bind(options)); - }); - } - - if (useSecrets) - { - elsa - .UseSecrets() - .UseSecretsManagement(management => - { - management.ConfigureOptions(options => configuration.GetSection("Secrets:Management").Bind(options)); - if (sqlDatabaseProvider == SqlDatabaseProvider.SqlServer) - management.UseEntityFrameworkCore(ef => - { - ef.UseContextPooling = useDbContextPooling; - ef.UseSqlServer(sqlServerConnectionString); - }); - else if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql) - management.UseEntityFrameworkCore(ef => - { - ef.UseContextPooling = useDbContextPooling; - ef.UsePostgreSql(postgresConnectionString); - }); - else - management.UseEntityFrameworkCore(ef => - { - ef.UseContextPooling = useDbContextPooling; - ef.UseSqlite(sp => sp.GetSqliteConnectionString()); - }); - }) - .UseSecretsApi() - .UseSecretsScripting(); - } - - //elsa.UseRetention(r => - //{ - // r.SweepInterval = TimeSpan.FromHours(5); - // r.AddDeletePolicy("Delete all finished workflows", sp => - // { - // var filter = new RetentionWorkflowInstanceFilter - // { - // WorkflowStatus = WorkflowStatus.Finished - // }; - // return filter; - // }); - //}); - - if (useMultitenancy) - { - elsa.UseTenants(tenants => - { - tenants.ConfigureMultitenancy(options => - { - options.TenantResolverPipelineBuilder - .Append() - .Append() - .Append() - .Append(); - }); - - if (useTenantsFromConfiguration) - { - tenants.UseConfigurationBasedTenantsProvider(options => configuration.GetSection("Multitenancy").Bind(options)); - } - else - { - tenants.UseStoreBasedTenantsProvider(); - - tenants.UseTenantManagement(management => - { - if (persistenceProvider == PersistenceProvider.MongoDb) - management.UseMongoDb(); - if (persistenceProvider == PersistenceProvider.Dapper) - throw new NotSupportedException("Dapper is not supported for tenant management."); - if (persistenceProvider == PersistenceProvider.EntityFrameworkCore) - { - management.UseEntityFrameworkCore(ef => - { - ef.UseContextPooling = useDbContextPooling; - if (sqlDatabaseProvider == SqlDatabaseProvider.Sqlite) ef.UseSqlite(sqliteConnectionString); - if (sqlDatabaseProvider == SqlDatabaseProvider.SqlServer) ef.UseSqlServer(sqlServerConnectionString); - if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql) ef.UsePostgreSql(postgresConnectionString); - if (sqlDatabaseProvider == SqlDatabaseProvider.Citus) ef.UsePostgreSql(citusConnectionString); - if (sqlDatabaseProvider == SqlDatabaseProvider.YugabyteDb) ef.UsePostgreSql(yugabyteDbConnectionString); - if (sqlDatabaseProvider == SqlDatabaseProvider.Oracle) - ef.UseOracle(oracleConnectionString, new() - { - SchemaName = "ELSA" - }); -#if !NET9_0 - if (sqlDatabaseProvider == SqlDatabaseProvider.MySql) - ef.UseMySql(mySqlConnectionString); -#endif - if (sqlDatabaseProvider == SqlDatabaseProvider.CockroachDb) ef.UsePostgreSql(cockroachDbConnectionString); - }); - } - }); - - tenants.UseTenantManagementEndpoints(); - } - }); - - elsa.UseTenantHttpRouting(tenantHttpRouting => - { - // Override the tenant header name with a custom one. - tenantHttpRouting.WithTenantHeader("X-Tenant-ID"); - }); - } - - elsa.UseWebhooks(webhooks => webhooks.ConfigureSinks += options => builder.Configuration.GetSection("Webhooks").Bind(options)); - elsa.InstallDropIns(options => options.DropInRootDirectory = Path.Combine(Directory.GetCurrentDirectory(), "App_Data", "DropIns")); - elsa.AddSwagger(); + elsa.AddFastEndpointsAssembly(); - //ConfigureForTest?.Invoke(elsa); }); - // Obfuscate HTTP request headers. - builder.Services.AddActivityStateFilter(); - // Optionally configure recurring tasks using alternative schedules. builder.Services.Configure(options => { @@ -624,25 +145,11 @@ public static class DependencyInjection builder.Services.Configure(options => options.Ttl = TimeSpan.FromSeconds(10)); builder.Services.Configure(options => options.CacheDuration = TimeSpan.FromDays(1)); builder.Services.Configure(options => options.DefaultIncidentStrategy = typeof(ContinueWithIncidentsStrategy)); - builder.Services.AddHealthChecks(); - builder.Services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().WithExposedHeaders("*"))); - + //builder.Services.AddHealthChecks(); builder.Services.AddScoped(); } - ///// - ///// The main entry point for the application made public for end to end testing. - ///// - //[UsedImplicitly] - //public partial class Program - //{ - // /// - // /// Set by the test runner to configure the module for testing. - // /// - // public static Action? ConfigureForTest { get; set; } - //} - public static void UseWorkflowFramework(this IApplicationBuilder app) { //try @@ -659,27 +166,13 @@ public static class DependencyInjection if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); - // CORS. - app.UseCors(); - // Health checks. //app.MapHealthChecks("/"); - // Routing used for SignalR. - app.UseRouting(); - - // Multitenancy. - if (useMultitenancy) - app.UseTenants(); - - // Elsa API endpoints for designer. - var routePrefix = app.ApplicationServices.GetRequiredService>().Value.RoutePrefix; - app.UseWorkflowsApi(routePrefix); - // Captures unhandled exceptions and returns a JSON response. app.UseJsonSerializationErrorHandler(); - - app.UseWorkflows(); + + //app.UseWorkflows(); } }