@effect-app/infra 4.0.0-beta.26 → 4.0.0-beta.260
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1966 -0
- package/_check.sh +1 -1
- package/dist/CUPS.d.ts +30 -11
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +35 -14
- package/dist/ClusterCosmos.d.ts +64 -0
- package/dist/ClusterCosmos.d.ts.map +1 -0
- package/dist/ClusterCosmos.js +487 -0
- package/dist/ClusterServiceBus.d.ts +67 -0
- package/dist/ClusterServiceBus.d.ts.map +1 -0
- package/dist/ClusterServiceBus.js +82 -0
- package/dist/ContextProvider.d.ts +34 -0
- package/dist/ContextProvider.d.ts.map +1 -0
- package/dist/ContextProvider.js +40 -0
- package/dist/Emailer/Sendgrid.d.ts +111 -147
- package/dist/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/Emailer/Sendgrid.js +24 -19
- package/dist/Emailer/fake.d.ts +2 -2
- package/dist/Emailer/fake.d.ts.map +1 -1
- package/dist/Emailer/fake.js +4 -4
- package/dist/MainFiberSet.d.ts +12 -9
- package/dist/MainFiberSet.d.ts.map +1 -1
- package/dist/MainFiberSet.js +10 -6
- package/dist/QueueMaker/SQLQueue.d.ts +8 -9
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +138 -120
- package/dist/QueueMaker/errors.d.ts +5 -3
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/QueueMaker/errors.js +4 -2
- package/dist/QueueMaker/memQueue.d.ts +10 -6
- package/dist/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +84 -68
- package/dist/QueueMaker/sbqueue.d.ts +9 -5
- package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/QueueMaker/sbqueue.js +60 -58
- package/dist/RequestFiberSet.d.ts +10 -7
- package/dist/RequestFiberSet.d.ts.map +1 -1
- package/dist/RequestFiberSet.js +13 -8
- package/dist/SQL/Model.d.ts +468 -0
- package/dist/SQL/Model.d.ts.map +1 -0
- package/dist/SQL/Model.js +469 -0
- package/dist/SQL.d.ts +2 -0
- package/dist/SQL.d.ts.map +1 -0
- package/dist/{adapters/SQL.js → SQL.js} +1 -1
- package/dist/ServiceBus.d.ts +61 -0
- package/dist/ServiceBus.d.ts.map +1 -0
- package/dist/ServiceBus.js +108 -0
- package/dist/Store/Cosmos/query.d.ts +15 -4
- package/dist/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/Store/Cosmos/query.js +179 -41
- package/dist/Store/Cosmos.d.ts +3 -3
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +344 -246
- package/dist/Store/Disk.d.ts +5 -5
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +78 -38
- package/dist/Store/Memory.d.ts +7 -10
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +326 -66
- package/dist/Store/SQL/Pg.d.ts +4 -0
- package/dist/Store/SQL/Pg.d.ts.map +1 -0
- package/dist/Store/SQL/Pg.js +232 -0
- package/dist/Store/SQL/query.d.ts +49 -0
- package/dist/Store/SQL/query.d.ts.map +1 -0
- package/dist/Store/SQL/query.js +527 -0
- package/dist/Store/SQL.d.ts +21 -0
- package/dist/Store/SQL.d.ts.map +1 -0
- package/dist/Store/SQL.js +449 -0
- package/dist/Store/codeFilter.d.ts +5 -5
- package/dist/Store/codeFilter.d.ts.map +1 -1
- package/dist/Store/codeFilter.js +6 -3
- package/dist/Store/index.d.ts +7 -5
- package/dist/Store/index.d.ts.map +1 -1
- package/dist/Store/index.js +18 -5
- package/dist/Store/utils.d.ts +4 -3
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +5 -5
- package/dist/WorkflowEngineCosmos.d.ts +29 -0
- package/dist/WorkflowEngineCosmos.d.ts.map +1 -0
- package/dist/WorkflowEngineCosmos.js +521 -0
- package/dist/WorkflowEngineSqlite.d.ts +24 -0
- package/dist/WorkflowEngineSqlite.d.ts.map +1 -0
- package/dist/WorkflowEngineSqlite.js +550 -0
- package/dist/arbs.d.ts +2 -2
- package/dist/arbs.d.ts.map +1 -1
- package/dist/arbs.js +5 -3
- package/dist/codec.d.ts +5 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +5 -0
- package/dist/cosmos-client.d.ts +16 -0
- package/dist/cosmos-client.d.ts.map +1 -0
- package/dist/cosmos-client.js +11 -0
- package/dist/errorReporter.d.ts +7 -5
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +23 -27
- package/dist/errors.d.ts +1 -1
- package/dist/fileUtil.d.ts +2 -2
- package/dist/fileUtil.d.ts.map +1 -1
- package/dist/fileUtil.js +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/internal/RequestContextMiddleware.d.ts +5 -0
- package/dist/internal/RequestContextMiddleware.d.ts.map +1 -0
- package/dist/internal/RequestContextMiddleware.js +45 -0
- package/dist/internal/auth.d.ts +53 -0
- package/dist/internal/auth.d.ts.map +1 -0
- package/dist/internal/auth.js +180 -0
- package/dist/internal/events.d.ts +11 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +49 -0
- package/dist/internal/health.d.ts +3 -0
- package/dist/internal/health.d.ts.map +1 -0
- package/dist/internal/health.js +5 -0
- package/dist/layerUtils.d.ts +32 -0
- package/dist/layerUtils.d.ts.map +1 -0
- package/dist/layerUtils.js +17 -0
- package/dist/logger/jsonLogger.d.ts +2 -2
- package/dist/logger/jsonLogger.d.ts.map +1 -1
- package/dist/logger/jsonLogger.js +5 -3
- package/dist/logger/logFmtLogger.d.ts +2 -2
- package/dist/logger/logFmtLogger.d.ts.map +1 -1
- package/dist/logger/logFmtLogger.js +3 -3
- package/dist/logger/shared.d.ts +3 -3
- package/dist/logger/shared.d.ts.map +1 -1
- package/dist/logger/shared.js +5 -5
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/memQueue.d.ts +15 -0
- package/dist/memQueue.d.ts.map +1 -0
- package/dist/memQueue.js +21 -0
- package/dist/middlewares.d.ts +10 -0
- package/dist/middlewares.d.ts.map +1 -0
- package/dist/{api/middlewares.js → middlewares.js} +1 -1
- package/dist/mongo-client.d.ts +11 -0
- package/dist/mongo-client.d.ts.map +1 -0
- package/dist/mongo-client.js +15 -0
- package/dist/otel.d.ts +75 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +65 -0
- package/dist/rateLimit.d.ts +12 -4
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +7 -12
- package/dist/redis-client.d.ts +42 -0
- package/dist/redis-client.d.ts.map +1 -0
- package/dist/redis-client.js +98 -0
- package/dist/reportError.d.ts +4 -0
- package/dist/reportError.d.ts.map +1 -0
- package/dist/reportError.js +28 -0
- package/dist/routing/middleware/RouterMiddleware.d.ts +16 -0
- package/dist/routing/middleware/RouterMiddleware.d.ts.map +1 -0
- package/dist/{api/routing → routing}/middleware/RouterMiddleware.js +1 -1
- package/dist/routing/middleware/middleware.d.ts +48 -0
- package/dist/routing/middleware/middleware.d.ts.map +1 -0
- package/dist/routing/middleware/middleware.js +128 -0
- package/dist/routing/middleware.d.ts +3 -0
- package/dist/routing/middleware.d.ts.map +1 -0
- package/dist/{api/routing → routing}/middleware.js +1 -2
- package/dist/routing/schema/jwt.d.ts +4 -0
- package/dist/routing/schema/jwt.d.ts.map +1 -0
- package/dist/routing/schema/jwt.js +13 -0
- package/dist/routing/tsort.d.ts +8 -0
- package/dist/routing/tsort.d.ts.map +1 -0
- package/dist/routing/tsort.js +51 -0
- package/dist/routing/utils.d.ts +19 -0
- package/dist/routing/utils.d.ts.map +1 -0
- package/dist/routing/utils.js +45 -0
- package/dist/routing.d.ts +184 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +236 -0
- package/dist/test.d.ts +3 -3
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +2 -2
- package/dist/util.d.ts +3 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +14 -0
- package/dist/vitest.d.ts +1 -1
- package/docs/cluster-storage.md +26 -0
- package/docs/workflow-engine.md +262 -0
- package/examples/query.ts +47 -39
- package/package.json +31 -345
- package/run.sh +1 -0
- package/src/CUPS.ts +52 -13
- package/src/ClusterCosmos.ts +954 -0
- package/src/ClusterServiceBus.ts +242 -0
- package/src/{api/ContextProvider.ts → ContextProvider.ts} +19 -16
- package/src/Emailer/Sendgrid.ts +82 -59
- package/src/Emailer/fake.ts +3 -3
- package/src/MainFiberSet.ts +12 -10
- package/src/QueueMaker/SQLQueue.ts +153 -156
- package/src/QueueMaker/errors.ts +3 -1
- package/src/QueueMaker/memQueue.ts +113 -107
- package/src/QueueMaker/sbqueue.ts +78 -90
- package/src/RequestFiberSet.ts +13 -8
- package/src/{adapters/SQL → SQL}/Model.ts +42 -41
- package/src/ServiceBus.ts +219 -0
- package/src/Store/Cosmos/query.ts +216 -52
- package/src/Store/Cosmos.ts +493 -353
- package/src/Store/Disk.ts +109 -69
- package/src/Store/Memory.ts +365 -96
- package/src/Store/SQL/Pg.ts +363 -0
- package/src/Store/SQL/query.ts +603 -0
- package/src/Store/SQL.ts +735 -0
- package/src/Store/codeFilter.ts +8 -5
- package/src/Store/index.ts +21 -6
- package/src/Store/utils.ts +26 -24
- package/src/WorkflowEngineCosmos.ts +719 -0
- package/src/WorkflowEngineSqlite.ts +813 -0
- package/src/arbs.ts +5 -3
- package/src/{adapters/cosmos-client.ts → cosmos-client.ts} +5 -3
- package/src/errorReporter.ts +66 -76
- package/src/fileUtil.ts +1 -1
- package/src/index.ts +2 -1
- package/src/{api/internal → internal}/RequestContextMiddleware.ts +23 -6
- package/src/internal/auth.ts +272 -0
- package/src/{api/internal → internal}/events.ts +22 -13
- package/src/{api/layerUtils.ts → layerUtils.ts} +14 -10
- package/src/logger/jsonLogger.ts +4 -2
- package/src/logger/logFmtLogger.ts +2 -2
- package/src/logger/shared.ts +5 -4
- package/src/{adapters/memQueue.ts → memQueue.ts} +5 -4
- package/src/{adapters/mongo-client.ts → mongo-client.ts} +4 -2
- package/src/otel.ts +152 -0
- package/src/rateLimit.ts +34 -23
- package/src/{adapters/redis-client.ts → redis-client.ts} +7 -3
- package/src/{api/reportError.ts → reportError.ts} +3 -2
- package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +5 -4
- package/src/{api/routing → routing}/middleware/middleware.ts +62 -17
- package/src/routing/middleware.ts +4 -0
- package/src/{api/routing → routing}/schema/jwt.ts +2 -1
- package/src/{api/routing → routing}/utils.ts +2 -1
- package/src/routing.ts +768 -0
- package/src/test.ts +2 -2
- package/test/auth.test.ts +101 -0
- package/test/cluster-cosmos.test.ts +503 -0
- package/test/cluster-servicebus.test.ts +180 -0
- package/test/contextProvider.test.ts +15 -12
- package/test/controller.test.ts +28 -32
- package/test/cosmos-query.test.ts +159 -0
- package/test/dist/_check-agg-infer.test-d.d.ts +2 -0
- package/test/dist/_check-agg-infer.test-d.d.ts.map +1 -0
- package/test/dist/_check-agg-infer.test-d.js +19 -0
- package/test/dist/_check-proj-infer.test-d.d.ts +2 -0
- package/test/dist/_check-proj-infer.test-d.d.ts.map +1 -0
- package/test/dist/_check-proj-infer.test-d.js +16 -0
- package/test/dist/_check-tighten.test-d.d.ts +2 -0
- package/test/dist/_check-tighten.test-d.d.ts.map +1 -0
- package/test/dist/_check-tighten.test-d.js +21 -0
- package/test/dist/auth.test.d.ts.map +1 -0
- package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
- package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
- package/test/dist/contextProvider.test.d.ts.map +1 -1
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/cosmos-query.test.d.ts.map +1 -0
- package/test/dist/date-query.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +30 -12
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +17 -10
- package/test/dist/query.test.d.ts.map +1 -1
- package/test/dist/rawQuery.test.d.ts.map +1 -1
- package/test/dist/repository-ext.test.d.ts.map +1 -0
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/dist/router-generator.test.d.ts.map +1 -0
- package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
- package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
- package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
- package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
- package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
- package/test/dist/sql-store.test.d.ts.map +1 -0
- package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
- package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
- package/test/fixtures.ts +16 -9
- package/test/layerUtils.test.ts +2 -2
- package/test/query.test.ts +905 -40
- package/test/rawQuery.test.ts +340 -22
- package/test/repository-ext.test.ts +62 -0
- package/test/requires.test.ts +10 -5
- package/test/router-generator.test.ts +187 -0
- package/test/routing-interruptibility.test.ts +66 -0
- package/test/rpc-context-map-streaming.test.ts +262 -0
- package/test/rpc-e2e-invalidation.test.ts +256 -0
- package/test/rpc-multi-middleware.test.ts +85 -10
- package/test/rpc-stream-fullstack.test.ts +304 -0
- package/test/sql-store.test.ts +1711 -0
- package/test/validateSample.test.ts +26 -14
- package/test/workflow-engine-cosmos.test.ts +354 -0
- package/test/workflow-engine-sqlite.test.ts +299 -0
- package/tsconfig.examples.json +1 -1
- package/tsconfig.json +2 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +35 -35
- package/tsconfig.test.json +2 -2
- package/dist/Emailer/service.d.ts +0 -55
- package/dist/Emailer/service.d.ts.map +0 -1
- package/dist/Emailer/service.js +0 -6
- package/dist/Emailer.d.ts +0 -2
- package/dist/Emailer.d.ts.map +0 -1
- package/dist/Emailer.js +0 -2
- package/dist/Model/Repository/ext.d.ts +0 -41
- package/dist/Model/Repository/ext.d.ts.map +0 -1
- package/dist/Model/Repository/ext.js +0 -65
- package/dist/Model/Repository/internal/internal.d.ts +0 -59
- package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
- package/dist/Model/Repository/internal/internal.js +0 -316
- package/dist/Model/Repository/legacy.d.ts +0 -19
- package/dist/Model/Repository/legacy.d.ts.map +0 -1
- package/dist/Model/Repository/legacy.js +0 -2
- package/dist/Model/Repository/makeRepo.d.ts +0 -49
- package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
- package/dist/Model/Repository/makeRepo.js +0 -24
- package/dist/Model/Repository/service.d.ts +0 -89
- package/dist/Model/Repository/service.d.ts.map +0 -1
- package/dist/Model/Repository/service.js +0 -2
- package/dist/Model/Repository/validation.d.ts +0 -42
- package/dist/Model/Repository/validation.d.ts.map +0 -1
- package/dist/Model/Repository/validation.js +0 -32
- package/dist/Model/Repository.d.ts +0 -6
- package/dist/Model/Repository.d.ts.map +0 -1
- package/dist/Model/Repository.js +0 -6
- package/dist/Model/dsl.d.ts +0 -32
- package/dist/Model/dsl.d.ts.map +0 -1
- package/dist/Model/dsl.js +0 -44
- package/dist/Model/filter/filterApi.d.ts +0 -30
- package/dist/Model/filter/filterApi.d.ts.map +0 -1
- package/dist/Model/filter/filterApi.js +0 -2
- package/dist/Model/filter/types/errors.d.ts +0 -29
- package/dist/Model/filter/types/errors.d.ts.map +0 -1
- package/dist/Model/filter/types/errors.js +0 -2
- package/dist/Model/filter/types/fields.d.ts +0 -15
- package/dist/Model/filter/types/fields.d.ts.map +0 -1
- package/dist/Model/filter/types/fields.js +0 -2
- package/dist/Model/filter/types/path/common.d.ts +0 -316
- package/dist/Model/filter/types/path/common.d.ts.map +0 -1
- package/dist/Model/filter/types/path/common.js +0 -2
- package/dist/Model/filter/types/path/eager.d.ts +0 -95
- package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
- package/dist/Model/filter/types/path/eager.js +0 -31
- package/dist/Model/filter/types/path/index.d.ts +0 -4
- package/dist/Model/filter/types/path/index.d.ts.map +0 -1
- package/dist/Model/filter/types/path/index.js +0 -3
- package/dist/Model/filter/types/utils.d.ts +0 -79
- package/dist/Model/filter/types/utils.d.ts.map +0 -1
- package/dist/Model/filter/types/utils.js +0 -2
- package/dist/Model/filter/types/validator.d.ts +0 -30
- package/dist/Model/filter/types/validator.d.ts.map +0 -1
- package/dist/Model/filter/types/validator.js +0 -2
- package/dist/Model/filter/types.d.ts +0 -5
- package/dist/Model/filter/types.d.ts.map +0 -1
- package/dist/Model/filter/types.js +0 -7
- package/dist/Model/query/dsl.d.ts +0 -248
- package/dist/Model/query/dsl.d.ts.map +0 -1
- package/dist/Model/query/dsl.js +0 -104
- package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
- package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
- package/dist/Model/query/new-kid-interpreter.js +0 -165
- package/dist/Model/query.d.ts +0 -15
- package/dist/Model/query.d.ts.map +0 -1
- package/dist/Model/query.js +0 -3
- package/dist/Model.d.ts +0 -4
- package/dist/Model.d.ts.map +0 -1
- package/dist/Model.js +0 -4
- package/dist/Operations.d.ts +0 -55
- package/dist/Operations.d.ts.map +0 -1
- package/dist/Operations.js +0 -102
- package/dist/OperationsRepo.d.ts +0 -41
- package/dist/OperationsRepo.d.ts.map +0 -1
- package/dist/OperationsRepo.js +0 -14
- package/dist/QueueMaker/service.d.ts +0 -11
- package/dist/QueueMaker/service.d.ts.map +0 -1
- package/dist/QueueMaker/service.js +0 -4
- package/dist/RequestContext.d.ts +0 -63
- package/dist/RequestContext.d.ts.map +0 -1
- package/dist/RequestContext.js +0 -49
- package/dist/Store/ContextMapContainer.d.ts +0 -14
- package/dist/Store/ContextMapContainer.d.ts.map +0 -1
- package/dist/Store/ContextMapContainer.js +0 -16
- package/dist/Store/service.d.ts +0 -108
- package/dist/Store/service.d.ts.map +0 -1
- package/dist/Store/service.js +0 -71
- package/dist/Store.d.ts +0 -2
- package/dist/Store.d.ts.map +0 -1
- package/dist/Store.js +0 -2
- package/dist/adapters/SQL/Model.d.ts +0 -479
- package/dist/adapters/SQL/Model.d.ts.map +0 -1
- package/dist/adapters/SQL/Model.js +0 -478
- package/dist/adapters/SQL.d.ts +0 -2
- package/dist/adapters/SQL.d.ts.map +0 -1
- package/dist/adapters/ServiceBus.d.ts +0 -58
- package/dist/adapters/ServiceBus.d.ts.map +0 -1
- package/dist/adapters/ServiceBus.js +0 -99
- package/dist/adapters/cosmos-client.d.ts +0 -14
- package/dist/adapters/cosmos-client.d.ts.map +0 -1
- package/dist/adapters/cosmos-client.js +0 -9
- package/dist/adapters/index.d.ts +0 -2
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -2
- package/dist/adapters/logger.d.ts +0 -9
- package/dist/adapters/logger.d.ts.map +0 -1
- package/dist/adapters/logger.js +0 -3
- package/dist/adapters/memQueue.d.ts +0 -13
- package/dist/adapters/memQueue.d.ts.map +0 -1
- package/dist/adapters/memQueue.js +0 -20
- package/dist/adapters/mongo-client.d.ts +0 -10
- package/dist/adapters/mongo-client.d.ts.map +0 -1
- package/dist/adapters/mongo-client.js +0 -13
- package/dist/adapters/redis-client.d.ts +0 -39
- package/dist/adapters/redis-client.d.ts.map +0 -1
- package/dist/adapters/redis-client.js +0 -94
- package/dist/api/ContextProvider.d.ts +0 -31
- package/dist/api/ContextProvider.d.ts.map +0 -1
- package/dist/api/ContextProvider.js +0 -38
- package/dist/api/codec.d.ts +0 -5
- package/dist/api/codec.d.ts.map +0 -1
- package/dist/api/codec.js +0 -5
- package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
- package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
- package/dist/api/internal/RequestContextMiddleware.js +0 -35
- package/dist/api/internal/auth.d.ts +0 -15
- package/dist/api/internal/auth.d.ts.map +0 -1
- package/dist/api/internal/auth.js +0 -47
- package/dist/api/internal/events.d.ts +0 -9
- package/dist/api/internal/events.d.ts.map +0 -1
- package/dist/api/internal/events.js +0 -42
- package/dist/api/internal/health.d.ts +0 -3
- package/dist/api/internal/health.d.ts.map +0 -1
- package/dist/api/internal/health.js +0 -5
- package/dist/api/layerUtils.d.ts +0 -24
- package/dist/api/layerUtils.d.ts.map +0 -1
- package/dist/api/layerUtils.js +0 -16
- package/dist/api/middlewares.d.ts +0 -10
- package/dist/api/middlewares.d.ts.map +0 -1
- package/dist/api/reportError.d.ts +0 -4
- package/dist/api/reportError.d.ts.map +0 -1
- package/dist/api/reportError.js +0 -27
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +0 -15
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/middleware.d.ts +0 -9
- package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/middleware.js +0 -92
- package/dist/api/routing/middleware.d.ts +0 -4
- package/dist/api/routing/middleware.d.ts.map +0 -1
- package/dist/api/routing/schema/jwt.d.ts +0 -4
- package/dist/api/routing/schema/jwt.d.ts.map +0 -1
- package/dist/api/routing/schema/jwt.js +0 -12
- package/dist/api/routing/tsort.d.ts +0 -8
- package/dist/api/routing/tsort.d.ts.map +0 -1
- package/dist/api/routing/tsort.js +0 -51
- package/dist/api/routing/utils.d.ts +0 -19
- package/dist/api/routing/utils.d.ts.map +0 -1
- package/dist/api/routing/utils.js +0 -44
- package/dist/api/routing.d.ts +0 -138
- package/dist/api/routing.d.ts.map +0 -1
- package/dist/api/routing.js +0 -166
- package/dist/api/setupRequest.d.ts +0 -12
- package/dist/api/setupRequest.d.ts.map +0 -1
- package/dist/api/setupRequest.js +0 -44
- package/dist/api/util.d.ts +0 -3
- package/dist/api/util.d.ts.map +0 -1
- package/dist/api/util.js +0 -14
- package/eslint.config.mjs +0 -24
- package/src/Emailer/service.ts +0 -52
- package/src/Emailer.ts +0 -1
- package/src/Model/Repository/ext.ts +0 -283
- package/src/Model/Repository/internal/internal.ts +0 -577
- package/src/Model/Repository/legacy.ts +0 -27
- package/src/Model/Repository/makeRepo.ts +0 -139
- package/src/Model/Repository/service.ts +0 -627
- package/src/Model/Repository/validation.ts +0 -31
- package/src/Model/Repository.ts +0 -5
- package/src/Model/dsl.ts +0 -128
- package/src/Model/filter/filterApi.ts +0 -60
- package/src/Model/filter/types/errors.ts +0 -47
- package/src/Model/filter/types/fields.ts +0 -50
- package/src/Model/filter/types/path/common.ts +0 -404
- package/src/Model/filter/types/path/eager.ts +0 -298
- package/src/Model/filter/types/path/index.ts +0 -4
- package/src/Model/filter/types/utils.ts +0 -128
- package/src/Model/filter/types/validator.ts +0 -46
- package/src/Model/filter/types.ts +0 -6
- package/src/Model/query/dsl.ts +0 -2110
- package/src/Model/query/new-kid-interpreter.ts +0 -210
- package/src/Model/query.ts +0 -13
- package/src/Model.ts +0 -3
- package/src/Operations.ts +0 -235
- package/src/OperationsRepo.ts +0 -16
- package/src/QueueMaker/service.ts +0 -17
- package/src/RequestContext.ts +0 -63
- package/src/Store/ContextMapContainer.ts +0 -20
- package/src/Store/service.ts +0 -184
- package/src/Store.ts +0 -1
- package/src/adapters/ServiceBus.ts +0 -209
- package/src/adapters/index.ts +0 -0
- package/src/adapters/logger.ts +0 -3
- package/src/api/internal/auth.ts +0 -68
- package/src/api/routing/middleware.ts +0 -6
- package/src/api/routing.ts +0 -598
- package/src/api/setupRequest.ts +0 -84
- /package/src/{adapters/SQL.ts → SQL.ts} +0 -0
- /package/src/{api/codec.ts → codec.ts} +0 -0
- /package/src/{api/internal → internal}/health.ts +0 -0
- /package/src/{api/middlewares.ts → middlewares.ts} +0 -0
- /package/src/{api/routing → routing}/tsort.ts +0 -0
- /package/src/{api/util.ts → util.ts} +0 -0
package/dist/util.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function snipValue(value) {
|
|
2
|
+
if (!value) {
|
|
3
|
+
return value;
|
|
4
|
+
}
|
|
5
|
+
return Array.isArray(value)
|
|
6
|
+
? value.map(snipString)
|
|
7
|
+
: typeof value === "string" && value.length > 50
|
|
8
|
+
? snipString(value)
|
|
9
|
+
: value;
|
|
10
|
+
}
|
|
11
|
+
export function snipString(value) {
|
|
12
|
+
return value.length > 255 ? value.slice(0, 255) + "...snip" : value;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy91dGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sVUFBVSxTQUFTLENBQUMsS0FBNkM7SUFDckUsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQztRQUN6QixDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7UUFDdkIsQ0FBQyxDQUFDLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLEVBQUU7WUFDaEQsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUM7WUFDbkIsQ0FBQyxDQUFDLEtBQUssQ0FBQTtBQUNYLENBQUM7QUFFRCxNQUFNLFVBQVUsVUFBVSxDQUFDLEtBQWE7SUFDdEMsT0FBTyxLQUFLLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUE7QUFDckUsQ0FBQyJ9
|
package/dist/vitest.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from "@effect/vitest";
|
|
2
2
|
export * from "./test.js";
|
|
3
|
-
//# sourceMappingURL=
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidml0ZXN0LmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdml0ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsZ0JBQWdCLENBQUE7QUFDOUIsY0FBYyxXQUFXLENBQUEifQ==
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Cluster storage backends (Cosmos vs SQL)
|
|
2
|
+
|
|
3
|
+
`@effect-app/infra` now ships Cosmos-backed cluster storage:
|
|
4
|
+
|
|
5
|
+
- [`ClusterCosmos.layerMessageStorage`](../src/ClusterCosmos.ts)
|
|
6
|
+
- [`ClusterCosmos.layerRunnerStorage`](../src/ClusterCosmos.ts)
|
|
7
|
+
- [`ClusterCosmos.layer`](../src/ClusterCosmos.ts)
|
|
8
|
+
- [`ClusterCosmos.layerCosmos`](../src/ClusterCosmos.ts)
|
|
9
|
+
|
|
10
|
+
The closest baseline in Effect is `SqlMessageStorage` + `SqlRunnerStorage`.
|
|
11
|
+
|
|
12
|
+
## Comparison
|
|
13
|
+
|
|
14
|
+
| Aspect | `ClusterCosmos` | `SqlMessageStorage` + `SqlRunnerStorage` |
|
|
15
|
+
| ------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
16
|
+
| Backend dependency | Azure Cosmos DB | SQL database via `SqlClient` |
|
|
17
|
+
| Schema management | Container-only document model (no SQL migrations) | Creates / migrates SQL tables (`messages`, `replies`, `runners`, `locks`, migrations table) |
|
|
18
|
+
| Message/reply model | JSON docs split by partition key (`message::shardId`, `reply::requestId`) | Relational rows with SQL indexes and joins |
|
|
19
|
+
| Locking strategy | Optimistic concurrency (`_etag`) on lock docs | Dialect-aware SQL locking (including advisory locks on pg/mysql when enabled) |
|
|
20
|
+
| Horizontal behavior | Throughput/cost depends on partitioning and cross-partition queries | Throughput/cost depends on SQL indexing, query plans, and connection limits |
|
|
21
|
+
| Operational fit | Best when Cosmos is already your system DB | Best when the cluster already runs on SQL infrastructure |
|
|
22
|
+
|
|
23
|
+
## Practical guidance
|
|
24
|
+
|
|
25
|
+
- Pick **`ClusterCosmos`** when your platform standard is Cosmos and you want to avoid introducing SQL just for cluster storage.
|
|
26
|
+
- Pick **SQL storage** when you already have strong SQL ops tooling and prefer table/migration based durability.
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# Durable Workflow Engines (SQLite & Cosmos)
|
|
2
|
+
|
|
3
|
+
This package provides two custom durable `WorkflowEngine` implementations for
|
|
4
|
+
`@effect/workflow`:
|
|
5
|
+
|
|
6
|
+
- [`WorkflowEngineSqlite.ts`](../src/WorkflowEngineSqlite.ts) — SQL-backed (4 tables).
|
|
7
|
+
- [`WorkflowEngineCosmos.ts`](../src/WorkflowEngineCosmos.ts) — Azure Cosmos DB
|
|
8
|
+
(single container, per-execution partition key).
|
|
9
|
+
|
|
10
|
+
Both implement the low-level `WorkflowEngine.Encoded` contract from
|
|
11
|
+
`effect/unstable/workflow/WorkflowEngine` and wrap it with `makeUnsafe`. They are
|
|
12
|
+
drop-in alternatives to Effect's built-in `ClusterWorkflowEngine`, trading
|
|
13
|
+
cluster-grade routing for a much lighter operational footprint: they need only a
|
|
14
|
+
database, not the full cluster stack (ShardManager, Runners, MessageStorage).
|
|
15
|
+
|
|
16
|
+
This document explains what they provide, how they differ from
|
|
17
|
+
`ClusterWorkflowEngine`, and how they behave during blue/green deployments.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. What these engines provide
|
|
22
|
+
|
|
23
|
+
Both engines persist the complete durable-execution state and recover it after a
|
|
24
|
+
restart. They are at **parity with `ClusterWorkflowEngine` on durability**:
|
|
25
|
+
|
|
26
|
+
| Capability | Provided | How |
|
|
27
|
+
| --------------------------------- | -------- | ------------------------------------------------------------------------ |
|
|
28
|
+
| Durable execution state | ✅ | exec / activity / deferred / clock rows, schema-encoded payloads+results |
|
|
29
|
+
| Restart recovery | ✅ | recovery poller re-drives `running` executions with an expired lease |
|
|
30
|
+
| Activity replay | ✅ | keyed by `(executionId, name, attempt)`; completed results replay |
|
|
31
|
+
| Durable clocks (`DurableClock`) | ✅ | clock row + clock poller; survives restart |
|
|
32
|
+
| Suspend / resume | ✅ | deferred completions persisted, polled, re-drive on completion |
|
|
33
|
+
| Idempotency / exactly-once writes | ✅ | first-writer-wins (`ON CONFLICT DO NOTHING` / batch `Create`) |
|
|
34
|
+
| Multi-process safety | ✅\* | etag optimistic-concurrency (OCC) + worker lease |
|
|
35
|
+
|
|
36
|
+
\* With caveats — see [§4 split-brain](#4-concurrency--split-brain) and
|
|
37
|
+
[§5 blue/green](#5-bluegreen-deployment-behavior).
|
|
38
|
+
|
|
39
|
+
### Persistence layout
|
|
40
|
+
|
|
41
|
+
**SQLite** — 4 tables ([`WorkflowEngineSqlite.ts:157-203`](../src/WorkflowEngineSqlite.ts#L157-L203)):
|
|
42
|
+
|
|
43
|
+
- `*_executions` — `execution_id` PK, `workflow_name`, `payload`, `parent`,
|
|
44
|
+
`status` (`running|complete|interrupted`), `suspended`, `interrupted`,
|
|
45
|
+
`completed_result`, `worker`, `lease_expires_at`, `etag`.
|
|
46
|
+
Index `(status, lease_expires_at)` for recovery scans.
|
|
47
|
+
- `*_activities` — PK `(execution_id, name, attempt)`, `result`.
|
|
48
|
+
- `*_deferred` — PK `(execution_id, name)`, `exit`.
|
|
49
|
+
- `*_clocks` — PK `(execution_id, name)`, `fire_at`. Index on `fire_at`.
|
|
50
|
+
|
|
51
|
+
**Cosmos** — single container, 4 document types, all partitioned by
|
|
52
|
+
`executionId` ([`WorkflowEngineCosmos.ts:69-149`](../src/WorkflowEngineCosmos.ts#L69-L149)):
|
|
53
|
+
|
|
54
|
+
- `exec` doc (the execution), `activity::<name>::<attempt>`,
|
|
55
|
+
`deferred::<name>`, `clock::<name>`.
|
|
56
|
+
- Sharing one partition key per execution makes all writes for an execution
|
|
57
|
+
TransactionalBatch-eligible.
|
|
58
|
+
|
|
59
|
+
Both encode payloads/results via schema round-tripping
|
|
60
|
+
(`S.fromJsonString(S.toCodecJson(...))`) so typed values (dates, branded IDs,
|
|
61
|
+
schema classes) survive restart — same strategy as `ClusterWorkflowEngine`.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 2. Execution & recovery model
|
|
66
|
+
|
|
67
|
+
These engines use a **poll-and-claim** model, not deterministic routing:
|
|
68
|
+
|
|
69
|
+
1. **Claim via lease.** A process claims an execution by writing its `workerId`
|
|
70
|
+
and `lease_expires_at = now + leaseTtl` under an etag OCC guard
|
|
71
|
+
([sqlite:455-475](../src/WorkflowEngineSqlite.ts#L455-L475)). If the lease is
|
|
72
|
+
held and unexpired by another worker, the claim is skipped.
|
|
73
|
+
2. **Heartbeat.** While driving, a fiber renews the lease every
|
|
74
|
+
`heartbeatInterval` ([sqlite:477-498](../src/WorkflowEngineSqlite.ts#L477-L498)).
|
|
75
|
+
3. **Recovery poller.** Every `recoveryInterval`, each process scans for
|
|
76
|
+
`status = 'running'` executions with a `NULL`/expired lease and re-drives them
|
|
77
|
+
locally ([sqlite:750-772](../src/WorkflowEngineSqlite.ts#L750-L772)).
|
|
78
|
+
4. **Clock poller.** Every `clockPollInterval`, each process scans for clocks with
|
|
79
|
+
`fire_at <= now`, inserts the deferred completion (first-writer-wins), deletes
|
|
80
|
+
the clock row, and re-drives ([sqlite:776-801](../src/WorkflowEngineSqlite.ts#L776-L801)).
|
|
81
|
+
|
|
82
|
+
### Default timings (both engines)
|
|
83
|
+
|
|
84
|
+
| Option | Default | Meaning |
|
|
85
|
+
| ------------------- | ------- | ---------------------------------------- |
|
|
86
|
+
| `leaseTtl` | 30s | how long a claim is held without renewal |
|
|
87
|
+
| `heartbeatInterval` | 10s | lease renewal cadence (< `leaseTtl`) |
|
|
88
|
+
| `recoveryInterval` | 15s | stale-execution rescan cadence |
|
|
89
|
+
| `clockPollInterval` | 5s | due-clock rescan cadence |
|
|
90
|
+
|
|
91
|
+
Sources: [sqlite:137-141](../src/WorkflowEngineSqlite.ts#L137-L141),
|
|
92
|
+
[cosmos:146-149](../src/WorkflowEngineCosmos.ts#L146-L149).
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 3. Comparison vs `ClusterWorkflowEngine`
|
|
97
|
+
|
|
98
|
+
Durability is matched. The gaps are about **routing efficiency, latency, and
|
|
99
|
+
targeting** — the things cluster sharding exists to provide.
|
|
100
|
+
|
|
101
|
+
| Aspect | These engines | `ClusterWorkflowEngine` |
|
|
102
|
+
| ---------------------------- | --------------------------------------------- | ---------------------------------------------------------- |
|
|
103
|
+
| Work routing | poll-and-race; every process scans the table | hash-ring routes each execution to one owning runner |
|
|
104
|
+
| Resume / signal latency | pull-based; up to poll interval (5–15s) | push-based; near-instant via entity messages |
|
|
105
|
+
| Interrupt across processes | flag in storage; remote fiber sees it on poll | interrupt message to owning runner; immediate |
|
|
106
|
+
| Load balancing | none; first claimer wins, recovery herds | even distribution by shard ownership |
|
|
107
|
+
| Node traits / host targeting | none; all processes are equal pollers | shard groups pin workloads to specific hosts (see §3.1) |
|
|
108
|
+
| Entity message ordering | concurrent `driveById` + OCC to resolve | serialized per-entity mailbox |
|
|
109
|
+
| Backpressure / capacity | none | mailbox capacity, termination timeout, poll intervals |
|
|
110
|
+
| Failover speed | wait lease expiry (~30s) then re-drive | fast shard rebalance on node leave |
|
|
111
|
+
| Split-brain window | wider (lease-expiry racing) | narrower (shard lock) |
|
|
112
|
+
| Operational cost | **just a DB** | full cluster stack (ShardManager, Runners, MessageStorage) |
|
|
113
|
+
|
|
114
|
+
**Cost at scale:** with N processes, every process recovery-polls the whole
|
|
115
|
+
executions table (15s) and clocks table (5s). On Cosmos the recovery scan is a
|
|
116
|
+
**cross-partition query** (fans across all partitions, RU-expensive). Cluster
|
|
117
|
+
scopes reads to owned shards.
|
|
118
|
+
|
|
119
|
+
### 3.1 Node traits / shard groups
|
|
120
|
+
|
|
121
|
+
`ClusterWorkflowEngine` supports **heterogeneous nodes** via shard groups:
|
|
122
|
+
|
|
123
|
+
- A runner declares which groups it hosts (`Runner.groups`,
|
|
124
|
+
`ShardingConfig.assignedShardGroups`).
|
|
125
|
+
- A workflow is pinned to a group with
|
|
126
|
+
`Workflow.make({...}).annotate(ClusterSchema.ShardGroup, () => "workflow")`.
|
|
127
|
+
- A separate hash ring per group means a workflow only ever lands on a runner
|
|
128
|
+
that hosts its group (e.g. "GPU workflows → GPU hosts only").
|
|
129
|
+
|
|
130
|
+
These engines have **no equivalent** — all processes are equal pollers. There is
|
|
131
|
+
no way to target a workflow at a subset of hosts. Note the trait granularity in
|
|
132
|
+
cluster is also coarse: opaque string group names, not arbitrary key/value label
|
|
133
|
+
selectors.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 4. Concurrency & split-brain
|
|
138
|
+
|
|
139
|
+
Safety rests on two mechanisms:
|
|
140
|
+
|
|
141
|
+
- **etag OCC** on the exec doc — a losing writer gets
|
|
142
|
+
`OptimisticConcurrencyException` (412/409) and backs off.
|
|
143
|
+
- **Worker lease** — only the lease holder drives; others skip while the lease is
|
|
144
|
+
live.
|
|
145
|
+
|
|
146
|
+
**The window:** `leaseTtl` is 30s, heartbeat 10s. If a process stalls (GC pause,
|
|
147
|
+
network partition) for longer than `leaseTtl` but is still alive, another process
|
|
148
|
+
claims the execution and both can run until the next exec write triggers an OCC
|
|
149
|
+
conflict.
|
|
150
|
+
|
|
151
|
+
- **Persisted activity results** are protected — first-writer-wins
|
|
152
|
+
(`ON CONFLICT DO NOTHING`), so the stored result is single-valued.
|
|
153
|
+
- **The activity _effect itself_** can still fire twice inside that window.
|
|
154
|
+
→ **Activities must be idempotent.** Same caveat applies to
|
|
155
|
+
`ClusterWorkflowEngine` (at-least-once during rebalance), but the lease-racing
|
|
156
|
+
window here is wider.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 5. Blue/green deployment behavior
|
|
161
|
+
|
|
162
|
+
### 5.1 Prerequisite: shared storage
|
|
163
|
+
|
|
164
|
+
- **Cosmos** — the container is always shared; blue and green see the same
|
|
165
|
+
executions. ✅
|
|
166
|
+
- **SQLite** — if each instance has its **own** database file, the storage is
|
|
167
|
+
**not shared**: green cannot see blue's in-flight executions, and they strand on
|
|
168
|
+
blue with no recovery path. **Blue/green with per-instance SQLite is broken.**
|
|
169
|
+
Use a shared volume, or treat the SQLite engine as single-node only.
|
|
170
|
+
|
|
171
|
+
The rest of this section assumes shared storage.
|
|
172
|
+
|
|
173
|
+
### 5.2 Overlap window (blue + green both alive)
|
|
174
|
+
|
|
175
|
+
- In-flight executions hold blue's lease and heartbeat every 10s. Green's recovery
|
|
176
|
+
poller sees the live lease and **skips** them. Blue keeps running them; green
|
|
177
|
+
only takes executions it newly starts. No double-run while blue heartbeats. ✅
|
|
178
|
+
- Both environments poll the same tables → ~2× scan load during overlap (on Cosmos,
|
|
179
|
+
2× cross-partition recovery RU). Minor, transient.
|
|
180
|
+
|
|
181
|
+
### 5.3 Cutover (blue terminated)
|
|
182
|
+
|
|
183
|
+
- Blue's leases stop renewing. After `leaseTtl` (30s) + green's `recoveryInterval`
|
|
184
|
+
(15s), green detects the stale executions, claims, and re-drives.
|
|
185
|
+
- **Failover gap ≈ 30–45s** — in-flight executions are paused that long
|
|
186
|
+
(pull-based, not instant).
|
|
187
|
+
- If blue is hard-killed mid-activity, the activity result was not persisted as
|
|
188
|
+
`Complete`, so green **re-runs** it (at-least-once). Non-idempotent side effects
|
|
189
|
+
double-fire — see [§4](#4-concurrency--split-brain).
|
|
190
|
+
|
|
191
|
+
### 5.4 Split-brain risk is elevated during deploys
|
|
192
|
+
|
|
193
|
+
Blue/green deliberately runs two versions concurrently. If blue is slow-draining
|
|
194
|
+
(SIGTERM grace overlapping a long activity) past `leaseTtl`, green claims and both
|
|
195
|
+
run. OCC + first-writer-wins protect persisted state; the activity-effect
|
|
196
|
+
double-fire window remains.
|
|
197
|
+
|
|
198
|
+
### 5.5 Sticky-lease — an accidental advantage
|
|
199
|
+
|
|
200
|
+
The lease model is **sticky to the starting worker**: an execution stays on the
|
|
201
|
+
process that started it as long as that process keeps heartbeating. With a
|
|
202
|
+
**graceful drain** (blue stops accepting new executions, finishes in-flight, then
|
|
203
|
+
terminates), in-flight workflows **complete on the version that started them** —
|
|
204
|
+
sidestepping cross-version replay entirely.
|
|
205
|
+
|
|
206
|
+
`ClusterWorkflowEngine` does the opposite: as soon as a blue runner deregisters,
|
|
207
|
+
its shards rebalance onto green (new-code) runners, so mid-flight cross-version
|
|
208
|
+
replay is the _default_ path during a deploy, not an edge case.
|
|
209
|
+
|
|
210
|
+
> ⚠️ **Missing drain hook.** Neither engine currently has a "stop claiming new
|
|
211
|
+
> executions" flag. To get the safe drain story above, this must be added (a flag
|
|
212
|
+
> that disables `tryClaim` for new work while letting heartbeats and in-flight
|
|
213
|
+
> drive continue). Until then, a graceful blue/green relies on the orchestrator
|
|
214
|
+
> keeping blue alive until in-flight work finishes.
|
|
215
|
+
|
|
216
|
+
### 5.6 Workflow versioning hazard (shared by both engines)
|
|
217
|
+
|
|
218
|
+
The real blue/green danger is **not** engine-specific — it is durable-execution
|
|
219
|
+
versioning:
|
|
220
|
+
|
|
221
|
+
- Replay must be deterministic. An execution started on v1 and replayed on v2 with
|
|
222
|
+
reordered/renamed activities mismatches activity-by-name → corrupt replay.
|
|
223
|
+
- A payload encoded with the v1 schema and decoded with an incompatible v2 schema
|
|
224
|
+
fails to decode.
|
|
225
|
+
|
|
226
|
+
Neither these engines nor `ClusterWorkflowEngine` solve this. Mitigations:
|
|
227
|
+
|
|
228
|
+
- **Additive-only schema changes** (no field removal/retype on in-flight payloads).
|
|
229
|
+
- **Do not reshape an in-flight workflow's step sequence**; version the workflow
|
|
230
|
+
name when the shape changes (`OrderV1` / `OrderV2`).
|
|
231
|
+
- **Drain in-flight executions before deploying breaking changes** (see §5.5).
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 6. When to use which
|
|
236
|
+
|
|
237
|
+
- **These engines** — durable workflows on a single process, or a small number of
|
|
238
|
+
processes over shared storage, where you want minimal ops (no cluster stack) and
|
|
239
|
+
can tolerate 5–15s resume latency and ~30–45s failover. Graceful drain on
|
|
240
|
+
deploy strongly recommended.
|
|
241
|
+
- **`ClusterWorkflowEngine`** — many processes, low-latency resume/interrupt, even
|
|
242
|
+
load distribution, or host targeting (shard groups). Worth the cluster stack
|
|
243
|
+
when you actually need those.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 7. Summary cheat-sheet
|
|
248
|
+
|
|
249
|
+
| Dimension | These engines | ClusterWorkflowEngine |
|
|
250
|
+
| ------------------------------- | --------------------------- | --------------------------------- |
|
|
251
|
+
| Durability / restart recovery | ✅ parity | ✅ |
|
|
252
|
+
| Activity replay & idempotency | ✅ parity | ✅ |
|
|
253
|
+
| Failover speed | ~30–45s (poll) | fast (push rebalance) |
|
|
254
|
+
| Resume / interrupt latency | 5–15s (pull) | near-instant (push) |
|
|
255
|
+
| Load balancing | ❌ | ✅ (shard ownership) |
|
|
256
|
+
| Host targeting / node traits | ❌ | ✅ (shard groups) |
|
|
257
|
+
| Split-brain window | wider (lease race) | narrower (shard lock) |
|
|
258
|
+
| Activity double-fire on cutover | possible — need idempotency | possible — need idempotency |
|
|
259
|
+
| Version-skew replay safety | unsolved — discipline only | unsolved — discipline only |
|
|
260
|
+
| In-flight version stickiness | sticky to starter (+ drain) | migrates to new code on rebalance |
|
|
261
|
+
| SQLite blue/green | needs shared storage | n/a |
|
|
262
|
+
| Operational cost | just a DB | full cluster stack |
|
package/examples/query.ts
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
import { Effect, Layer, ManagedRuntime, S, Schema } from "effect-app"
|
|
2
|
-
import { makeRepo } from "../src/Model.js"
|
|
3
|
-
import { and, make, one, or, order, page, project, QueryWhere, where } from "../src/Model/query.js"
|
|
4
|
-
import { MemoryStoreLive } from "../src/Store/Memory.js"
|
|
5
1
|
import { expectTypeOf } from "@effect/vitest"
|
|
2
|
+
import * as Effect from "effect-app/Effect"
|
|
3
|
+
import * as Layer from "effect-app/Layer"
|
|
4
|
+
import { makeRepo } from "effect-app/Model"
|
|
5
|
+
import { and, make, one, or, order, page, project, type QueryWhere, where } from "effect-app/Model/query"
|
|
6
|
+
import * as S from "effect-app/Schema"
|
|
7
|
+
import * as ManagedRuntime from "effect/ManagedRuntime"
|
|
8
|
+
import * as Struct from "effect/Struct"
|
|
9
|
+
import { MemoryStoreLive } from "../src/Store/Memory.js"
|
|
6
10
|
|
|
7
11
|
const str = S.Struct({ _tag: S.Literal("string"), value: S.String })
|
|
8
|
-
const num = S.Struct({ _tag: S.Literal("number"), value: S.
|
|
12
|
+
const num = S.Struct({ _tag: S.Literal("number"), value: S.Finite })
|
|
9
13
|
const someUnion = S.Union(str, num)
|
|
10
14
|
|
|
11
|
-
export class Something extends S.
|
|
12
|
-
id: S.StringId.
|
|
15
|
+
export class Something extends S.Opaque<Something>()(S.TaggedStruct("Something", {
|
|
16
|
+
id: S.StringId.withConstructorDefault,
|
|
13
17
|
displayName: S.NonEmptyString255,
|
|
14
|
-
n: S.Date.
|
|
15
|
-
union: someUnion.pipe(S.
|
|
16
|
-
}) {}
|
|
18
|
+
n: S.Date.withConstructorDefault,
|
|
19
|
+
union: someUnion.pipe(S.withConstructorDefault(Effect.succeed({ _tag: "string" as const, value: "hi" })))
|
|
20
|
+
})) {}
|
|
17
21
|
|
|
18
|
-
export class SomethingElse extends S.
|
|
19
|
-
id: S.StringId.
|
|
22
|
+
export class SomethingElse extends S.Opaque<SomethingElse>()(S.TaggedStruct("SomethingElse", {
|
|
23
|
+
id: S.StringId.withConstructorDefault,
|
|
20
24
|
banana: S.NonEmptyString255
|
|
21
|
-
}) {}
|
|
25
|
+
})) {}
|
|
22
26
|
|
|
23
27
|
const Union = S.Union(Something, SomethingElse)
|
|
24
28
|
|
|
@@ -38,15 +42,15 @@ export declare namespace SomethingElse {
|
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
const items = [
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
Something.make({ displayName: S.NonEmptyString255("Verona"), n: new Date("2020-01-01T00:00:00Z") }),
|
|
46
|
+
Something.make({ displayName: S.NonEmptyString255("Riley") }),
|
|
47
|
+
Something.make({
|
|
44
48
|
displayName: S.NonEmptyString255("Riley"),
|
|
45
49
|
n: new Date("2020-01-01T00:00:00Z"),
|
|
46
50
|
union: { _tag: "number", value: 1 }
|
|
47
51
|
}),
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
SomethingElse.make({ banana: S.NonEmptyString255("Banana") }),
|
|
53
|
+
SomethingElse.make({ banana: S.NonEmptyString255("Banana2") })
|
|
50
54
|
]
|
|
51
55
|
|
|
52
56
|
class SomethingRepo extends Effect.Service<SomethingRepo>()("SomethingRepo", {
|
|
@@ -78,7 +82,7 @@ const program = Effect.gen(function*() {
|
|
|
78
82
|
order("displayName"),
|
|
79
83
|
page({ take: 1 }),
|
|
80
84
|
one,
|
|
81
|
-
project(
|
|
85
|
+
project(Something.mapFields(Struct.pick(["id", "displayName"])))
|
|
82
86
|
)
|
|
83
87
|
|
|
84
88
|
const r2 = yield* somethingRepo.query(
|
|
@@ -100,31 +104,35 @@ const rt = ManagedRuntime.make(SomethingRepo.Test)
|
|
|
100
104
|
rt.runFork(program)
|
|
101
105
|
|
|
102
106
|
const test1 = make<Union.Encoded>().pipe(
|
|
103
|
-
where("union._tag", "string")
|
|
107
|
+
where("union._tag", "string")
|
|
104
108
|
)
|
|
105
109
|
|
|
106
|
-
expectTypeOf(test1).toEqualTypeOf<
|
|
107
|
-
|
|
108
|
-
readonly
|
|
109
|
-
readonly
|
|
110
|
-
readonly
|
|
110
|
+
expectTypeOf(test1).toEqualTypeOf<
|
|
111
|
+
QueryWhere<Union.Encoded, {
|
|
112
|
+
readonly _tag: "Something"
|
|
113
|
+
readonly id: string
|
|
114
|
+
readonly displayName: string
|
|
115
|
+
readonly n: string
|
|
111
116
|
readonly union: {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
}
|
|
117
|
+
readonly _tag: "string"
|
|
118
|
+
readonly value: string
|
|
119
|
+
}
|
|
120
|
+
}>
|
|
121
|
+
>()
|
|
116
122
|
|
|
117
123
|
const testneq1 = make<Union.Encoded>().pipe(
|
|
118
|
-
where("union._tag", "neq", "string")
|
|
124
|
+
where("union._tag", "neq", "string")
|
|
119
125
|
)
|
|
120
126
|
|
|
121
|
-
expectTypeOf(testneq1).toEqualTypeOf<
|
|
122
|
-
|
|
123
|
-
readonly
|
|
124
|
-
readonly
|
|
125
|
-
readonly
|
|
127
|
+
expectTypeOf(testneq1).toEqualTypeOf<
|
|
128
|
+
QueryWhere<Union.Encoded, {
|
|
129
|
+
readonly _tag: "Something"
|
|
130
|
+
readonly id: string
|
|
131
|
+
readonly displayName: string
|
|
132
|
+
readonly n: string
|
|
126
133
|
readonly union: {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
}
|
|
134
|
+
readonly _tag: "number"
|
|
135
|
+
readonly value: number
|
|
136
|
+
}
|
|
137
|
+
}>
|
|
138
|
+
>()
|