From 5be82dd9abb2d9e21c38e7fbaa6a117d7ea01e7f Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 11 Mar 2025 11:19:59 +0100 Subject: [PATCH] Add support for Citus and YugabyteDB integration Introduced Docker Compose configurations for Citus and YugabyteDB clusters and updated connection strings in `appsettings.json`. Modified `Program.cs` to enable Entity Framework Core support for both databases and updated the `SqlDatabaseProvider` enum accordingly. Adjusted the Docker Compose setup and bumped `Yarp.ReverseProxy` package version. --- Directory.Packages.props | 2 +- Elsa.sln | 2 + scripts/docker/docker-compose-citus.yml | 65 +++++++++++++++++++ scripts/docker/docker-compose-yugabyte.yml | 55 ++++++++++++++++ scripts/docker/docker-compose.yml | 17 ++++- .../Elsa.Server.LoadBalancer.csproj | 7 -- .../Enums/SqlDatabaseProvider.cs | 2 + src/apps/Elsa.Server.Web/Program.cs | 38 ++++++++--- src/apps/Elsa.Server.Web/appsettings.json | 2 + 9 files changed, 172 insertions(+), 18 deletions(-) create mode 100644 scripts/docker/docker-compose-citus.yml create mode 100644 scripts/docker/docker-compose-yugabyte.yml diff --git a/Directory.Packages.props b/Directory.Packages.props index 1d00a43cd..24aeb0565 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -113,7 +113,7 @@ - + diff --git a/Elsa.sln b/Elsa.sln index 23d1ee4cc..f78fa138b 100644 --- a/Elsa.sln +++ b/Elsa.sln @@ -322,6 +322,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{AA5ACF scripts\docker\build-and-run-all-in-one-web-docker.sh = scripts\docker\build-and-run-all-in-one-web-docker.sh scripts\docker\docker-compose.yml = scripts\docker\docker-compose.yml scripts\docker\docker-run-all-in-one-web.ps1 = scripts\docker\docker-run-all-in-one-web.ps1 + scripts\docker\docker-compose-citus.yml = scripts\docker\docker-compose-citus.yml + scripts\docker\docker-compose-yugabyte.yml = scripts\docker\docker-compose-yugabyte.yml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "elsa-studio", "elsa-studio", "{DFFE6199-B5A7-4BA8-A5E1-77D0426C6468}" diff --git a/scripts/docker/docker-compose-citus.yml b/scripts/docker/docker-compose-citus.yml new file mode 100644 index 000000000..3575fac53 --- /dev/null +++ b/scripts/docker/docker-compose-citus.yml @@ -0,0 +1,65 @@ +services: + # Coordinator Node + citus-coordinator: + image: citusdata/citus:latest + container_name: citus-coordinator + ports: + - "9700:5432" + environment: + POSTGRES_DB: citus + POSTGRES_USER: citus + POSTGRES_PASSWORD: citus + CITUS_HOST: citus-coordinator + command: [ "postgres", "-c", "wal_level=logical" ] + healthcheck: + test: ["CMD", "pg_isready", "-U", "citus"] + interval: 10s + retries: 5 + networks: + - citus-network + + # Worker Node 1 + citus-worker-1: + image: citusdata/citus:latest + container_name: citus-worker-1 + environment: + POSTGRES_DB: citus + POSTGRES_USER: citus + POSTGRES_PASSWORD: citus + CITUS_HOST: citus-worker-1 + command: [ "postgres", "-c", "wal_level=logical" ] + depends_on: + - citus-coordinator + networks: + - citus-network + + # Worker Node 2 + citus-worker-2: + image: citusdata/citus:latest + container_name: citus-worker-2 + environment: + POSTGRES_DB: citus + POSTGRES_USER: citus + POSTGRES_PASSWORD: citus + CITUS_HOST: citus-worker-2 + command: [ "postgres", "-c", "wal_level=logical" ] + depends_on: + - citus-coordinator + networks: + - citus-network + + # Citus Manager (optional - registers worker nodes automatically) + citus-manager: + image: citusdata/citus:latest + container_name: citus-manager + depends_on: + - citus-coordinator + - citus-worker-1 + - citus-worker-2 + command: [ "citus_setup" ] + networks: + - citus-network + +networks: + citus-network: + driver: bridge diff --git a/scripts/docker/docker-compose-yugabyte.yml b/scripts/docker/docker-compose-yugabyte.yml new file mode 100644 index 000000000..9dd6c489e --- /dev/null +++ b/scripts/docker/docker-compose-yugabyte.yml @@ -0,0 +1,55 @@ +version: '3.8' + +services: + yb-master: + image: yugabytedb/yugabyte:latest + container_name: yb-master + command: ["/home/yugabyte/bin/yb-master", "--fs_data_dirs=/mnt/data", "--master_addresses=yb-master:7100"] + ports: + - "7001:7000" # Master UI + networks: + - yugabytedb + environment: + - YB_ENABLED_IN_POSTGRES_MODE=1 + volumes: + - yb-master-data:/mnt/data + + yb-tserver-1: + image: yugabytedb/yugabyte:latest + container_name: yb-tserver-1 + command: ["/home/yugabyte/bin/yb-tserver", "--fs_data_dirs=/mnt/data", "--tserver_master_addrs=yb-master:7100", "--pgsql_proxy_bind_address=0.0.0.0:5433"] + ports: + - "5543:5433" # Changed from 5433 -> 5543 for PostgreSQL + - "9000:9000" # TServer UI + networks: + - yugabytedb + depends_on: + - yb-master + environment: + - YB_ENABLED_IN_POSTGRES_MODE=1 + volumes: + - yb-tserver-1-data:/mnt/data + + yb-tserver-2: + image: yugabytedb/yugabyte:latest + container_name: yb-tserver-2 + command: ["/home/yugabyte/bin/yb-tserver", "--fs_data_dirs=/mnt/data", "--tserver_master_addrs=yb-master:7100", "--pgsql_proxy_bind_address=0.0.0.0:5433"] + ports: + - "5544:5433" # Second worker node (internal) + - "9001:9000" # TServer UI + networks: + - yugabytedb + depends_on: + - yb-master + environment: + - YB_ENABLED_IN_POSTGRES_MODE=1 + volumes: + - yb-tserver-2-data:/mnt/data + +networks: + yugabytedb: + +volumes: + yb-master-data: + yb-tserver-1-data: + yb-tserver-2-data: diff --git a/scripts/docker/docker-compose.yml b/scripts/docker/docker-compose.yml index 193fd0d94..f7c8198b2 100644 --- a/scripts/docker/docker-compose.yml +++ b/scripts/docker/docker-compose.yml @@ -71,6 +71,20 @@ expose: - '3306' + citusdata: + image: citusdata/citus:13.0 + container_name: citus_cluster + environment: + POSTGRES_USER: citus + POSTGRES_PASSWORD: citus_password + POSTGRES_DB: citus + ports: + - "9700:5432" # Citus uses PostgreSQL default port; 9700 avoids conflicts with other Postgres services + volumes: + - citusdata_data:/var/lib/postgresql/data + + # (Other volume and network definitions) + redis: image: redis:latest ports: @@ -116,7 +130,7 @@ ports: - "4000:80" - "2525:25" - + networks: consul: @@ -124,5 +138,6 @@ volumes: mongodb_data: pgdata-3: sqlserver_data: + citusdata_data: elasticsearch-data: driver: local \ No newline at end of file diff --git a/src/apps/Elsa.Server.LoadBalancer/Elsa.Server.LoadBalancer.csproj b/src/apps/Elsa.Server.LoadBalancer/Elsa.Server.LoadBalancer.csproj index 1b2b2b688..ecf73e228 100644 --- a/src/apps/Elsa.Server.LoadBalancer/Elsa.Server.LoadBalancer.csproj +++ b/src/apps/Elsa.Server.LoadBalancer/Elsa.Server.LoadBalancer.csproj @@ -1,12 +1,5 @@ - - net9.0 - Linux - false - latest - - diff --git a/src/apps/Elsa.Server.Web/Enums/SqlDatabaseProvider.cs b/src/apps/Elsa.Server.Web/Enums/SqlDatabaseProvider.cs index 651163385..72aad1b57 100644 --- a/src/apps/Elsa.Server.Web/Enums/SqlDatabaseProvider.cs +++ b/src/apps/Elsa.Server.Web/Enums/SqlDatabaseProvider.cs @@ -6,6 +6,8 @@ public enum SqlDatabaseProvider Sqlite, MySql, PostgreSql, + Citus, + YugabyteDb, Oracle, CockroachDb } \ No newline at end of file diff --git a/src/apps/Elsa.Server.Web/Program.cs b/src/apps/Elsa.Server.Web/Program.cs index 85815a143..2818a232f 100644 --- a/src/apps/Elsa.Server.Web/Program.cs +++ b/src/apps/Elsa.Server.Web/Program.cs @@ -106,6 +106,8 @@ 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")!; @@ -151,7 +153,7 @@ services dapper.DbConnectionProvider = sp => { if (sqlDatabaseProvider == SqlDatabaseProvider.SqlServer) - return new SqlServerDbConnectionProvider(sqlServerConnectionString!); + return new SqlServerDbConnectionProvider(sqlServerConnectionString); else return new SqliteDbConnectionProvider(sqliteConnectionString); }; @@ -204,15 +206,19 @@ services identity.UseEntityFrameworkCore(ef => { if (sqlDatabaseProvider == SqlDatabaseProvider.SqlServer) - ef.UseSqlServer(sqlServerConnectionString!); + ef.UseSqlServer(sqlServerConnectionString); else if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql) - ef.UsePostgreSql(postgresConnectionString!); + ef.UsePostgreSql(postgresConnectionString); + else if (sqlDatabaseProvider == SqlDatabaseProvider.Citus) + ef.UsePostgreSql(citusConnectionString); + else if (sqlDatabaseProvider == SqlDatabaseProvider.YugabyteDb) + ef.UsePostgreSql(yugabyteDbConnectionString, configure: dbContextOptions => dbContextOptions.With()); #if !NET9_0 else if (sqlDatabaseProvider == SqlDatabaseProvider.MySql) ef.UseMySql(mySqlConnectionString); #endif else if (sqlDatabaseProvider == SqlDatabaseProvider.CockroachDb) - ef.UsePostgreSql(cockroachDbConnectionString!); + ef.UsePostgreSql(cockroachDbConnectionString); else if (sqlDatabaseProvider == SqlDatabaseProvider.Oracle) ef.UseOracle(oracleConnectionString, new() { SchemaName = "ELSA"}); @@ -248,15 +254,19 @@ services management.UseEntityFrameworkCore(ef => { if (sqlDatabaseProvider == SqlDatabaseProvider.SqlServer) - ef.UseSqlServer(sqlServerConnectionString!); + ef.UseSqlServer(sqlServerConnectionString); else if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql) - ef.UsePostgreSql(postgresConnectionString!); + ef.UsePostgreSql(postgresConnectionString); + else if (sqlDatabaseProvider == SqlDatabaseProvider.Citus) + ef.UsePostgreSql(citusConnectionString); + else if (sqlDatabaseProvider == SqlDatabaseProvider.YugabyteDb) + ef.UsePostgreSql(yugabyteDbConnectionString); #if !NET9_0 else if (sqlDatabaseProvider == SqlDatabaseProvider.MySql) ef.UseMySql(mySqlConnectionString); #endif else if (sqlDatabaseProvider == SqlDatabaseProvider.CockroachDb) - ef.UsePostgreSql(cockroachDbConnectionString!); + ef.UsePostgreSql(cockroachDbConnectionString); else if (sqlDatabaseProvider == SqlDatabaseProvider.Oracle) ef.UseOracle(oracleConnectionString, new() { SchemaName = "ELSA"}); @@ -299,7 +309,11 @@ services ef.DbContextOptionsBuilder = (_, db) => db.UseElsaSqlServer(migrationsAssembly, connectionString, null, configure => configure.CommandTimeout(60000)); } else if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql) - ef.UsePostgreSql(postgresConnectionString!); + ef.UsePostgreSql(postgresConnectionString); + else if (sqlDatabaseProvider == SqlDatabaseProvider.Citus) + ef.UsePostgreSql(citusConnectionString); + else if (sqlDatabaseProvider == SqlDatabaseProvider.YugabyteDb) + ef.UsePostgreSql(yugabyteDbConnectionString); #if !NET9_0 else if (sqlDatabaseProvider == SqlDatabaseProvider.MySql) ef.UseMySql(mySqlConnectionString); @@ -448,6 +462,10 @@ services ef.UseSqlServer(sqlServerConnectionString); else if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql) ef.UsePostgreSql(postgresConnectionString); + else if (sqlDatabaseProvider == SqlDatabaseProvider.Citus) + ef.UsePostgreSql(citusConnectionString); + else if (sqlDatabaseProvider == SqlDatabaseProvider.YugabyteDb) + ef.UsePostgreSql(yugabyteDbConnectionString); #if !NET9_0 else if (sqlDatabaseProvider == SqlDatabaseProvider.MySql) ef.UseMySql(mySqlConnectionString); @@ -540,7 +558,7 @@ services proto.PersistenceProvider = _ => { if (sqlDatabaseProvider == SqlDatabaseProvider.SqlServer) - return new SqlServerProvider(sqlServerConnectionString!, true, "", "proto_actor"); + return new SqlServerProvider(sqlServerConnectionString, true, "", "proto_actor"); return new SqliteProvider(new(sqliteConnectionString)); }; @@ -641,6 +659,8 @@ services 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 diff --git a/src/apps/Elsa.Server.Web/appsettings.json b/src/apps/Elsa.Server.Web/appsettings.json index e361f3077..9010bf944 100644 --- a/src/apps/Elsa.Server.Web/appsettings.json +++ b/src/apps/Elsa.Server.Web/appsettings.json @@ -15,6 +15,8 @@ "Sqlite": "Data Source=App_Data/elsa.sqlite.db;Cache=Shared;", "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",