@nestjs/workflows 0.0.1
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/LICENSE +23 -0
- package/README.md +50 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +8 -0
- package/dist/core/codecs/aes-gcm-payload.codec.d.ts +42 -0
- package/dist/core/codecs/aes-gcm-payload.codec.js +119 -0
- package/dist/core/codecs/index.d.ts +2 -0
- package/dist/core/codecs/index.js +2 -0
- package/dist/core/codecs/payload-codecs.d.ts +59 -0
- package/dist/core/codecs/payload-codecs.js +130 -0
- package/dist/core/index.d.ts +16 -0
- package/dist/core/index.js +21 -0
- package/dist/core/interfaces/clock.interface.d.ts +18 -0
- package/dist/core/interfaces/clock.interface.js +1 -0
- package/dist/core/interfaces/index.d.ts +9 -0
- package/dist/core/interfaces/index.js +9 -0
- package/dist/core/interfaces/leased-worker-options.interface.d.ts +94 -0
- package/dist/core/interfaces/leased-worker-options.interface.js +1 -0
- package/dist/core/interfaces/limits.interface.d.ts +92 -0
- package/dist/core/interfaces/limits.interface.js +1 -0
- package/dist/core/interfaces/payload-codec.interface.d.ts +64 -0
- package/dist/core/interfaces/payload-codec.interface.js +1 -0
- package/dist/core/interfaces/result-waiter-options.interface.d.ts +52 -0
- package/dist/core/interfaces/result-waiter-options.interface.js +1 -0
- package/dist/core/interfaces/retry-settings.interface.d.ts +71 -0
- package/dist/core/interfaces/retry-settings.interface.js +1 -0
- package/dist/core/interfaces/schedule-store.interface.d.ts +143 -0
- package/dist/core/interfaces/schedule-store.interface.js +1 -0
- package/dist/core/interfaces/schedule.interface.d.ts +106 -0
- package/dist/core/interfaces/schedule.interface.js +1 -0
- package/dist/core/interfaces/scheduler-options.interface.d.ts +152 -0
- package/dist/core/interfaces/scheduler-options.interface.js +1 -0
- package/dist/core/limits/index.d.ts +1 -0
- package/dist/core/limits/index.js +1 -0
- package/dist/core/limits/limits.d.ts +61 -0
- package/dist/core/limits/limits.js +130 -0
- package/dist/core/results/index.d.ts +1 -0
- package/dist/core/results/index.js +1 -0
- package/dist/core/results/result-waiter.d.ts +54 -0
- package/dist/core/results/result-waiter.js +140 -0
- package/dist/core/retries/index.d.ts +1 -0
- package/dist/core/retries/index.js +1 -0
- package/dist/core/retries/retry.d.ts +60 -0
- package/dist/core/retries/retry.js +107 -0
- package/dist/core/scheduling/cron.util.d.ts +52 -0
- package/dist/core/scheduling/cron.util.js +262 -0
- package/dist/core/scheduling/encoded-schedule.store.d.ts +26 -0
- package/dist/core/scheduling/encoded-schedule.store.js +54 -0
- package/dist/core/scheduling/in-memory-schedule.store.d.ts +20 -0
- package/dist/core/scheduling/in-memory-schedule.store.js +90 -0
- package/dist/core/scheduling/index.d.ts +3 -0
- package/dist/core/scheduling/index.js +3 -0
- package/dist/core/scheduling/rrule.util.d.ts +55 -0
- package/dist/core/scheduling/rrule.util.js +371 -0
- package/dist/core/scheduling/schedule-spec.d.ts +57 -0
- package/dist/core/scheduling/schedule-spec.js +233 -0
- package/dist/core/scheduling/scheduler.d.ts +134 -0
- package/dist/core/scheduling/scheduler.js +450 -0
- package/dist/core/scheduling/time-zone.util.d.ts +18 -0
- package/dist/core/scheduling/time-zone.util.js +88 -0
- package/dist/core/time/clock.d.ts +28 -0
- package/dist/core/time/clock.js +35 -0
- package/dist/core/time/duration.d.ts +21 -0
- package/dist/core/time/duration.js +30 -0
- package/dist/core/time/index.d.ts +2 -0
- package/dist/core/time/index.js +2 -0
- package/dist/core/utils/canonical.util.d.ts +2 -0
- package/dist/core/utils/canonical.util.js +4 -0
- package/dist/core/utils/maybe.util.d.ts +8 -0
- package/dist/core/utils/maybe.util.js +14 -0
- package/dist/core/utils/payload-place.util.d.ts +10 -0
- package/dist/core/utils/payload-place.util.js +32 -0
- package/dist/core/workers/index.d.ts +1 -0
- package/dist/core/workers/index.js +1 -0
- package/dist/core/workers/leased-worker.d.ts +86 -0
- package/dist/core/workers/leased-worker.js +280 -0
- package/dist/cqrs/decorators/index.d.ts +2 -0
- package/dist/cqrs/decorators/index.js +2 -0
- package/dist/cqrs/decorators/signal-on.decorator.d.ts +18 -0
- package/dist/cqrs/decorators/signal-on.decorator.js +34 -0
- package/dist/cqrs/decorators/start-on.decorator.d.ts +18 -0
- package/dist/cqrs/decorators/start-on.decorator.js +49 -0
- package/dist/cqrs/index.d.ts +3 -0
- package/dist/cqrs/index.js +5 -0
- package/dist/cqrs/interfaces/index.d.ts +4 -0
- package/dist/cqrs/interfaces/index.js +4 -0
- package/dist/cqrs/interfaces/signal-on-options.interface.d.ts +22 -0
- package/dist/cqrs/interfaces/signal-on-options.interface.js +1 -0
- package/dist/cqrs/interfaces/start-on-options.interface.d.ts +23 -0
- package/dist/cqrs/interfaces/start-on-options.interface.js +1 -0
- package/dist/cqrs/interfaces/workflow-dispatcher-context.interface.d.ts +10 -0
- package/dist/cqrs/interfaces/workflow-dispatcher-context.interface.js +1 -0
- package/dist/cqrs/interfaces/workflow-event-route.interface.d.ts +20 -0
- package/dist/cqrs/interfaces/workflow-event-route.interface.js +1 -0
- package/dist/cqrs/utils/event-routes.util.d.ts +7 -0
- package/dist/cqrs/utils/event-routes.util.js +22 -0
- package/dist/cqrs/workflow-event.publisher.d.ts +52 -0
- package/dist/cqrs/workflow-event.publisher.js +257 -0
- package/dist/cqrs/workflow-events.explorer.d.ts +27 -0
- package/dist/cqrs/workflow-events.explorer.js +92 -0
- package/dist/cqrs/workflows-cqrs.module.d.ts +10 -0
- package/dist/cqrs/workflows-cqrs.module.js +27 -0
- package/dist/decorators/index.d.ts +1 -0
- package/dist/decorators/index.js +1 -0
- package/dist/decorators/workflow.decorator.d.ts +7 -0
- package/dist/decorators/workflow.decorator.js +52 -0
- package/dist/errors/child-workflow-failed.error.d.ts +13 -0
- package/dist/errors/child-workflow-failed.error.js +14 -0
- package/dist/errors/index.d.ts +13 -0
- package/dist/errors/index.js +13 -0
- package/dist/errors/non-retryable-step.error.d.ts +4 -0
- package/dist/errors/non-retryable-step.error.js +7 -0
- package/dist/errors/step-failed.error.d.ts +15 -0
- package/dist/errors/step-failed.error.js +16 -0
- package/dist/errors/step-timeout.error.d.ts +5 -0
- package/dist/errors/step-timeout.error.js +8 -0
- package/dist/errors/workflow-definition.error.d.ts +10 -0
- package/dist/errors/workflow-definition.error.js +13 -0
- package/dist/errors/workflow-failed.error.d.ts +20 -0
- package/dist/errors/workflow-failed.error.js +17 -0
- package/dist/errors/workflow-id-conflict.error.d.ts +6 -0
- package/dist/errors/workflow-id-conflict.error.js +9 -0
- package/dist/errors/workflow-interrupt.error.d.ts +32 -0
- package/dist/errors/workflow-interrupt.error.js +19 -0
- package/dist/errors/workflow-non-determinism.error.d.ts +4 -0
- package/dist/errors/workflow-non-determinism.error.js +7 -0
- package/dist/errors/workflow-not-found.error.d.ts +10 -0
- package/dist/errors/workflow-not-found.error.js +13 -0
- package/dist/errors/workflow-result-timeout.error.d.ts +11 -0
- package/dist/errors/workflow-result-timeout.error.js +13 -0
- package/dist/errors/workflow-state.error.d.ts +11 -0
- package/dist/errors/workflow-state.error.js +14 -0
- package/dist/errors/workflow.error.d.ts +7 -0
- package/dist/errors/workflow.error.js +7 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/events/index.js +3 -0
- package/dist/events/workflow-events.interface.d.ts +145 -0
- package/dist/events/workflow-events.interface.js +1 -0
- package/dist/events/workflow-events.service.d.ts +17 -0
- package/dist/events/workflow-events.service.js +38 -0
- package/dist/events/workflows.channels.d.ts +3 -0
- package/dist/events/workflows.channels.js +9 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +23 -0
- package/dist/interfaces/index.d.ts +13 -0
- package/dist/interfaces/index.js +13 -0
- package/dist/interfaces/serialized-workflow-error.interface.d.ts +6 -0
- package/dist/interfaces/serialized-workflow-error.interface.js +1 -0
- package/dist/interfaces/workflow-client.interface.d.ts +156 -0
- package/dist/interfaces/workflow-client.interface.js +1 -0
- package/dist/interfaces/workflow-clock.interface.d.ts +7 -0
- package/dist/interfaces/workflow-clock.interface.js +1 -0
- package/dist/interfaces/workflow-context.interface.d.ts +241 -0
- package/dist/interfaces/workflow-context.interface.js +1 -0
- package/dist/interfaces/workflow-decorator-options.interface.d.ts +101 -0
- package/dist/interfaces/workflow-decorator-options.interface.js +1 -0
- package/dist/interfaces/workflow-instance.interface.d.ts +83 -0
- package/dist/interfaces/workflow-instance.interface.js +1 -0
- package/dist/interfaces/workflow-payload-codec.interface.d.ts +32 -0
- package/dist/interfaces/workflow-payload-codec.interface.js +1 -0
- package/dist/interfaces/workflow-retry-options.interface.d.ts +9 -0
- package/dist/interfaces/workflow-retry-options.interface.js +1 -0
- package/dist/interfaces/workflow-runner.interface.d.ts +11 -0
- package/dist/interfaces/workflow-runner.interface.js +1 -0
- package/dist/interfaces/workflow-schedule.interface.d.ts +104 -0
- package/dist/interfaces/workflow-schedule.interface.js +1 -0
- package/dist/interfaces/workflow-storage.interface.d.ts +4 -0
- package/dist/interfaces/workflow-storage.interface.js +1 -0
- package/dist/interfaces/workflow-store.interface.d.ts +488 -0
- package/dist/interfaces/workflow-store.interface.js +1 -0
- package/dist/interfaces/workflows-module-options.interface.d.ts +80 -0
- package/dist/interfaces/workflows-module-options.interface.js +1 -0
- package/dist/mysql/index.d.ts +5 -0
- package/dist/mysql/index.js +8 -0
- package/dist/mysql/interfaces/index.d.ts +1 -0
- package/dist/mysql/interfaces/index.js +1 -0
- package/dist/mysql/interfaces/mysql-workflow-store-options.interface.d.ts +25 -0
- package/dist/mysql/interfaces/mysql-workflow-store-options.interface.js +1 -0
- package/dist/mysql/key-limits.d.ts +30 -0
- package/dist/mysql/key-limits.js +41 -0
- package/dist/mysql/migrations/index.d.ts +7 -0
- package/dist/mysql/migrations/index.js +16 -0
- package/dist/mysql/migrations/initial.migration.d.ts +9 -0
- package/dist/mysql/migrations/initial.migration.js +104 -0
- package/dist/mysql/mysql-workflow.store.d.ts +197 -0
- package/dist/mysql/mysql-workflow.store.js +828 -0
- package/dist/postgres/errors/index.d.ts +1 -0
- package/dist/postgres/errors/index.js +2 -0
- package/dist/postgres/index.d.ts +5 -0
- package/dist/postgres/index.js +8 -0
- package/dist/postgres/interfaces/index.d.ts +1 -0
- package/dist/postgres/interfaces/index.js +1 -0
- package/dist/postgres/interfaces/postgres-workflow-store-options.interface.d.ts +22 -0
- package/dist/postgres/interfaces/postgres-workflow-store-options.interface.js +1 -0
- package/dist/postgres/migrations/index.d.ts +6 -0
- package/dist/postgres/migrations/index.js +15 -0
- package/dist/postgres/migrations/initial.migration.d.ts +6 -0
- package/dist/postgres/migrations/initial.migration.js +106 -0
- package/dist/postgres/postgres-workflow.store.d.ts +132 -0
- package/dist/postgres/postgres-workflow.store.js +586 -0
- package/dist/services/index.d.ts +6 -0
- package/dist/services/index.js +6 -0
- package/dist/services/workflow-client.service.d.ts +146 -0
- package/dist/services/workflow-client.service.js +436 -0
- package/dist/services/workflow-execution.service.d.ts +267 -0
- package/dist/services/workflow-execution.service.js +1076 -0
- package/dist/services/workflow-registry.service.d.ts +56 -0
- package/dist/services/workflow-registry.service.js +172 -0
- package/dist/services/workflow-scheduler.service.d.ts +54 -0
- package/dist/services/workflow-scheduler.service.js +173 -0
- package/dist/services/workflow-schedules.service.d.ts +60 -0
- package/dist/services/workflow-schedules.service.js +193 -0
- package/dist/services/workflow-worker.service.d.ts +92 -0
- package/dist/services/workflow-worker.service.js +468 -0
- package/dist/signals/index.d.ts +1 -0
- package/dist/signals/index.js +1 -0
- package/dist/signals/workflow.signal.d.ts +17 -0
- package/dist/signals/workflow.signal.js +28 -0
- package/dist/sql/rate-windows.d.ts +41 -0
- package/dist/sql/rate-windows.js +53 -0
- package/dist/sql/workflow-rows.d.ts +16 -0
- package/dist/sql/workflow-rows.js +102 -0
- package/dist/sql/workflow-schema.error.d.ts +21 -0
- package/dist/sql/workflow-schema.error.js +15 -0
- package/dist/storage/encoded-workflow.store.d.ts +71 -0
- package/dist/storage/encoded-workflow.store.js +201 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/workflow.storage.d.ts +55 -0
- package/dist/storage/workflow.storage.js +159 -0
- package/dist/stores/in-memory-workflow.store.d.ts +75 -0
- package/dist/stores/in-memory-workflow.store.js +380 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.js +1 -0
- package/dist/testing/assertions.d.ts +10 -0
- package/dist/testing/assertions.js +72 -0
- package/dist/testing/index.d.ts +38 -0
- package/dist/testing/index.js +1089 -0
- package/dist/testing/schedule-store.contract.d.ts +33 -0
- package/dist/testing/schedule-store.contract.js +161 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/journal-limits.util.d.ts +6 -0
- package/dist/utils/journal-limits.util.js +25 -0
- package/dist/utils/new-instance.util.d.ts +26 -0
- package/dist/utils/new-instance.util.js +87 -0
- package/dist/utils/normalize.util.d.ts +5 -0
- package/dist/utils/normalize.util.js +11 -0
- package/dist/utils/run-timeout.util.d.ts +3 -0
- package/dist/utils/run-timeout.util.js +15 -0
- package/dist/utils/schedule-spec.util.d.ts +16 -0
- package/dist/utils/schedule-spec.util.js +9 -0
- package/dist/utils/schedule-store.util.d.ts +15 -0
- package/dist/utils/schedule-store.util.js +44 -0
- package/dist/utils/serialize-error.util.d.ts +7 -0
- package/dist/utils/serialize-error.util.js +22 -0
- package/dist/utils/step-scope.util.d.ts +16 -0
- package/dist/utils/step-scope.util.js +38 -0
- package/dist/workflows.constants.d.ts +10 -0
- package/dist/workflows.constants.js +10 -0
- package/dist/workflows.module-definition.d.ts +4 -0
- package/dist/workflows.module-definition.js +6 -0
- package/dist/workflows.module.d.ts +24 -0
- package/dist/workflows.module.js +68 -0
- package/package.json +123 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../../sql/workflow-schema.error.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { PostgresWorkflowStore } from './postgres-workflow.store.js';
|
|
2
|
+
export { WorkflowSchemaError } from './errors/index.js';
|
|
3
|
+
export type { PostgresWorkflowStoreOptions } from './interfaces/index.js';
|
|
4
|
+
export { fromDrizzle, fromKysely, fromPg, fromPrisma, fromTypeOrm, type PrismaExecutorOptions } from '@nestjs/store-kit/postgres';
|
|
5
|
+
export type { SqlExecutor, SqlIsolationLevel, SqlTransaction, SqlTransactionOptions } from '@nestjs/store-kit/postgres';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// The `@nestjs/workflows/postgres` entry: the first-party PostgreSQL store. Nothing here imports a driver or an ORM:
|
|
2
|
+
// the executors (from @nestjs/store-kit, which every first-party store builds on) reach the client the application
|
|
3
|
+
// passes them.
|
|
4
|
+
// The store, and the error it fails startup with while its schema is behind
|
|
5
|
+
export { PostgresWorkflowStore } from './postgres-workflow.store.js';
|
|
6
|
+
export { WorkflowSchemaError } from './errors/index.js';
|
|
7
|
+
// Executors: the store's SQL through the application's pool or ORM, and its transactions
|
|
8
|
+
export { fromDrizzle, fromKysely, fromPg, fromPrisma, fromTypeOrm } from '@nestjs/store-kit/postgres';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './postgres-workflow-store-options.interface.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './postgres-workflow-store-options.interface.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SqlExecutor } from '@nestjs/store-kit/postgres';
|
|
2
|
+
/** What `new PostgresWorkflowStore(options, storage)` takes. */
|
|
3
|
+
export interface PostgresWorkflowStoreOptions {
|
|
4
|
+
/**
|
|
5
|
+
* How the store reaches the database: `fromPg(pool)`, `fromDrizzle(db)`, `fromTypeOrm(dataSource)`,
|
|
6
|
+
* `fromPrisma(prisma)` or `fromKysely(db)`. The store's own transactions run on it, and `start()` and `signal()`
|
|
7
|
+
* with `{ transaction }` take that client's transaction object.
|
|
8
|
+
*/
|
|
9
|
+
executor: SqlExecutor<'postgres'>;
|
|
10
|
+
/**
|
|
11
|
+
* The schema that holds the store's tables, created by its first migration: keep it for the store alone. Letters,
|
|
12
|
+
* digits and underscores, not starting with a digit, at most 63 characters. Default: `'nest_workflows'`.
|
|
13
|
+
*/
|
|
14
|
+
schema?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Apply the store's pending migrations at startup, in one transaction under an advisory lock, so processes that
|
|
17
|
+
* start together migrate once. With `false`, startup fails with a `WorkflowSchemaError` while the schema is behind
|
|
18
|
+
* this version of the package: apply them with `npx nest-workflows migrate`, or with your own migration tool
|
|
19
|
+
* (`PostgresWorkflowStore.migrationSql()`). Default: `true`, except when `NODE_ENV` is `production`.
|
|
20
|
+
*/
|
|
21
|
+
migrate?: boolean;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { StoreSchema } from '@nestjs/store-kit/postgres';
|
|
2
|
+
/**
|
|
3
|
+
* PostgresWorkflowStore's schema: every version of it, in order (a new one goes last, and none ever changes once
|
|
4
|
+
* released), and what the store, its statics and `nest-workflows` do with them.
|
|
5
|
+
*/
|
|
6
|
+
export declare const workflowStoreSchema: StoreSchema;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { StoreSchema } from '@nestjs/store-kit/postgres';
|
|
2
|
+
import { WorkflowSchemaError } from '../../sql/workflow-schema.error.js';
|
|
3
|
+
import { initialMigration } from './initial.migration.js';
|
|
4
|
+
/**
|
|
5
|
+
* PostgresWorkflowStore's schema: every version of it, in order (a new one goes last, and none ever changes once
|
|
6
|
+
* released), and what the store, its statics and `nest-workflows` do with them.
|
|
7
|
+
*/
|
|
8
|
+
export const workflowStoreSchema = new StoreSchema({
|
|
9
|
+
packageName: '@nestjs/workflows',
|
|
10
|
+
storeName: 'PostgresWorkflowStore',
|
|
11
|
+
command: 'nest-workflows',
|
|
12
|
+
defaultSchema: 'nest_workflows',
|
|
13
|
+
migrations: [initialMigration],
|
|
14
|
+
createError: (message, details) => new WorkflowSchemaError(message, details),
|
|
15
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { StoreMigration } from '@nestjs/store-kit/postgres';
|
|
2
|
+
/**
|
|
3
|
+
* The store's tables. Times are epoch milliseconds from the engine's clock (`bigint`); inputs, outputs, errors,
|
|
4
|
+
* payloads, journal entries and schedule specs are the engine's JSON (`jsonb`).
|
|
5
|
+
*/
|
|
6
|
+
export declare const initialMigration: StoreMigration;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The store's tables. Times are epoch milliseconds from the engine's clock (`bigint`); inputs, outputs, errors,
|
|
3
|
+
* payloads, journal entries and schedule specs are the engine's JSON (`jsonb`).
|
|
4
|
+
*/
|
|
5
|
+
export const initialMigration = {
|
|
6
|
+
version: 1,
|
|
7
|
+
name: 'initial',
|
|
8
|
+
up: (s) => [
|
|
9
|
+
`CREATE TABLE ${s}.instances (
|
|
10
|
+
id text PRIMARY KEY,
|
|
11
|
+
workflow text NOT NULL,
|
|
12
|
+
version integer NOT NULL,
|
|
13
|
+
parent_id text,
|
|
14
|
+
parent_close text,
|
|
15
|
+
concurrency_key text,
|
|
16
|
+
rate_limit_key text,
|
|
17
|
+
priority integer NOT NULL DEFAULT 0,
|
|
18
|
+
schedule_id text,
|
|
19
|
+
scheduled_at bigint,
|
|
20
|
+
status text NOT NULL,
|
|
21
|
+
input jsonb,
|
|
22
|
+
output jsonb,
|
|
23
|
+
error jsonb,
|
|
24
|
+
wake_at bigint,
|
|
25
|
+
lease_token text,
|
|
26
|
+
lease_owner text,
|
|
27
|
+
lease_until bigint,
|
|
28
|
+
cancel_requested boolean NOT NULL DEFAULT false,
|
|
29
|
+
terminate_requested boolean NOT NULL DEFAULT false,
|
|
30
|
+
cancel_reason text,
|
|
31
|
+
deadline bigint,
|
|
32
|
+
custom_status jsonb,
|
|
33
|
+
signal_cursor bigint NOT NULL,
|
|
34
|
+
runs integer NOT NULL DEFAULT 0,
|
|
35
|
+
created_at bigint NOT NULL,
|
|
36
|
+
updated_at bigint NOT NULL
|
|
37
|
+
)`,
|
|
38
|
+
// One row per step, sleep, wait or compensation; `seq` keeps them in first-write order.
|
|
39
|
+
`CREATE TABLE ${s}.journal (
|
|
40
|
+
seq bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
41
|
+
instance_id text NOT NULL REFERENCES ${s}.instances (id) ON DELETE CASCADE,
|
|
42
|
+
name text NOT NULL,
|
|
43
|
+
entry jsonb NOT NULL,
|
|
44
|
+
CONSTRAINT journal_name UNIQUE (instance_id, name)
|
|
45
|
+
)`,
|
|
46
|
+
// The signals a suspended instance waits for.
|
|
47
|
+
`CREATE TABLE ${s}.waits (
|
|
48
|
+
instance_id text NOT NULL REFERENCES ${s}.instances (id) ON DELETE CASCADE,
|
|
49
|
+
position integer NOT NULL,
|
|
50
|
+
signal text NOT NULL,
|
|
51
|
+
key text,
|
|
52
|
+
PRIMARY KEY (instance_id, position)
|
|
53
|
+
)`,
|
|
54
|
+
`CREATE TABLE ${s}.signals (
|
|
55
|
+
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
56
|
+
name text NOT NULL,
|
|
57
|
+
key text,
|
|
58
|
+
dedupe_id text,
|
|
59
|
+
payload jsonb,
|
|
60
|
+
created_at bigint NOT NULL,
|
|
61
|
+
CONSTRAINT signals_dedupe UNIQUE (name, dedupe_id)
|
|
62
|
+
)`,
|
|
63
|
+
`CREATE TABLE ${s}.schedules (
|
|
64
|
+
id text PRIMARY KEY,
|
|
65
|
+
workflow text NOT NULL,
|
|
66
|
+
declared boolean NOT NULL,
|
|
67
|
+
spec jsonb NOT NULL,
|
|
68
|
+
input jsonb,
|
|
69
|
+
paused boolean NOT NULL,
|
|
70
|
+
wake_at bigint,
|
|
71
|
+
state jsonb NOT NULL,
|
|
72
|
+
revision integer NOT NULL,
|
|
73
|
+
lease_token text,
|
|
74
|
+
lease_owner text,
|
|
75
|
+
lease_until bigint,
|
|
76
|
+
created_at bigint NOT NULL,
|
|
77
|
+
updated_at bigint NOT NULL
|
|
78
|
+
)`,
|
|
79
|
+
// The rate-limit windows claims count: the workflow's own (`key` '', which no instance key is) and one per key.
|
|
80
|
+
`CREATE TABLE ${s}.rate_limits (
|
|
81
|
+
workflow text NOT NULL,
|
|
82
|
+
key text NOT NULL,
|
|
83
|
+
window_end bigint NOT NULL,
|
|
84
|
+
count integer NOT NULL,
|
|
85
|
+
PRIMARY KEY (workflow, key)
|
|
86
|
+
)`,
|
|
87
|
+
// What claims look for: due instances.
|
|
88
|
+
`CREATE INDEX instances_due ON ${s}.instances (wake_at) WHERE wake_at IS NOT NULL`,
|
|
89
|
+
`CREATE INDEX instances_created ON ${s}.instances (created_at, id)`,
|
|
90
|
+
// What purges and list() by status look for.
|
|
91
|
+
`CREATE INDEX instances_status ON ${s}.instances (status, updated_at)`,
|
|
92
|
+
// What a claim counts for a concurrency limit: live leases, by workflow and key.
|
|
93
|
+
`CREATE INDEX instances_leased ON ${s}.instances (workflow, concurrency_key) WHERE lease_until IS NOT NULL`,
|
|
94
|
+
// What list({ parentId }) and closing a parent's children look for.
|
|
95
|
+
`CREATE INDEX instances_parent ON ${s}.instances (parent_id, created_at) WHERE parent_id IS NOT NULL`,
|
|
96
|
+
// What list({ scheduleId }) and a schedule's overlap check look for.
|
|
97
|
+
`CREATE INDEX instances_schedule ON ${s}.instances (schedule_id, created_at) WHERE schedule_id IS NOT NULL`,
|
|
98
|
+
`CREATE INDEX waits_signal ON ${s}.waits (signal, key)`,
|
|
99
|
+
`CREATE INDEX signals_lookup ON ${s}.signals (name, key, id)`,
|
|
100
|
+
// What claims look for: due schedules.
|
|
101
|
+
`CREATE INDEX schedules_due ON ${s}.schedules (wake_at) WHERE wake_at IS NOT NULL`,
|
|
102
|
+
`CREATE INDEX schedules_workflow ON ${s}.schedules (workflow, id)`,
|
|
103
|
+
// What purges look for: windows that ended.
|
|
104
|
+
`CREATE INDEX rate_limits_end ON ${s}.rate_limits (window_end)`,
|
|
105
|
+
],
|
|
106
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { type OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { type MigrationSqlOptions } from '@nestjs/store-kit/postgres';
|
|
3
|
+
import type { WorkflowInstance, WorkflowStatus } from '../interfaces/workflow-instance.interface.js';
|
|
4
|
+
import type { NewWorkflowInstance, NewWorkflowSignal, WorkflowCancelRequest, WorkflowClaim, WorkflowClaimRequest, WorkflowInstanceDetails, WorkflowListQuery, WorkflowPurgeQuery, WorkflowPurgeResult, WorkflowReopen, WorkflowScheduleClaimRequest, WorkflowScheduleQuery, WorkflowScheduleRecord, WorkflowScheduleSave, WorkflowScheduleWrite, WorkflowSignalQuery, WorkflowSignalRecord, WorkflowSignalResult, WorkflowStore, WorkflowWrite } from '../interfaces/workflow-store.interface.js';
|
|
5
|
+
import type { WorkflowStorage } from '../storage/workflow.storage.js';
|
|
6
|
+
import type { PostgresWorkflowStoreOptions } from './interfaces/postgres-workflow-store-options.interface.js';
|
|
7
|
+
/**
|
|
8
|
+
* The first-party `WorkflowStore` on PostgreSQL, through the client the application already has (`fromPg()`,
|
|
9
|
+
* `fromDrizzle()`, `fromTypeOrm()`, `fromPrisma()`, `fromKysely()`). It keeps its tables in a schema of its own
|
|
10
|
+
* (`nest_workflows` by default), which its migrations create and bring up to date, and it joins the application's
|
|
11
|
+
* transactions for `start()` and `signal()` with `{ transaction }`.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* @Module({
|
|
15
|
+
* imports: [WorkflowsModule.forRoot()],
|
|
16
|
+
* providers: [
|
|
17
|
+
* {
|
|
18
|
+
* provide: PostgresWorkflowStore,
|
|
19
|
+
* inject: [getDrizzleToken(), WorkflowStorage],
|
|
20
|
+
* useFactory: (db: Database, storage: WorkflowStorage) => new PostgresWorkflowStore({ executor: fromDrizzle(db) }, storage),
|
|
21
|
+
* },
|
|
22
|
+
* ],
|
|
23
|
+
* })
|
|
24
|
+
* export class AppModule {}
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* Given `storage`, it registers itself (`storage.registerSource(this)`), as every store does. It checks its schema,
|
|
28
|
+
* or migrates it (`migrate`), in `onModuleInit` (so before the worker starts), or at its first call outside Nest.
|
|
29
|
+
*/
|
|
30
|
+
export declare class PostgresWorkflowStore implements WorkflowStore, OnModuleInit {
|
|
31
|
+
/**
|
|
32
|
+
* The SQL of the store's migrations, for teams that apply migrations with their own tool (drizzle-kit, TypeORM,
|
|
33
|
+
* Prisma Migrate, Flyway...) and run the store with `migrate: false`: from version `from` (default `0`, a new
|
|
34
|
+
* database) to `to` (default: the version this version of the package needs), with the bookkeeping that tells the
|
|
35
|
+
* store which versions a schema has. A schema's version is `SELECT max(version) FROM <schema>.migrations`.
|
|
36
|
+
* Downgrades aren't supported. From version 0 it starts with `CREATE SCHEMA IF NOT EXISTS`, which needs the CREATE
|
|
37
|
+
* privilege on the database even when the schema exists: drop that statement if someone created the schema for you.
|
|
38
|
+
* With `statementBreakpoints`, drizzle-kit's `--> statement-breakpoint` separates the statements, for a custom
|
|
39
|
+
* drizzle-kit migration: its migrator then runs them one at a time, which PGlite needs.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* // drizzle/0003_workflows.sql, created empty by `npx drizzle-kit generate --custom --name=workflows`
|
|
43
|
+
* writeFileSync('drizzle/0003_workflows.sql', PostgresWorkflowStore.migrationSql({ statementBreakpoints: true }));
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
static migrationSql(options?: MigrationSqlOptions): string;
|
|
47
|
+
/** The schema version this version of the package needs: its last migration. */
|
|
48
|
+
static readonly schemaVersion: number;
|
|
49
|
+
private readonly logger;
|
|
50
|
+
private readonly executor;
|
|
51
|
+
private readonly schema;
|
|
52
|
+
private readonly t;
|
|
53
|
+
/**
|
|
54
|
+
* Serializes signals with each other (exclusive) and with suspensions that register waits (shared), until the
|
|
55
|
+
* transaction ends: signal ids become visible in id order, and a signal can't slip between a suspension's check for
|
|
56
|
+
* missed signals and its commit.
|
|
57
|
+
*/
|
|
58
|
+
private readonly signalLock;
|
|
59
|
+
/** The schema migrated (`migrate`) or checked before the first statement: see `onModuleInit()`. */
|
|
60
|
+
private readonly readiness;
|
|
61
|
+
constructor(options: PostgresWorkflowStoreOptions, storage?: WorkflowStorage);
|
|
62
|
+
/** Migrates the schema (`migrate`) or checks it, before the worker starts: startup fails if it can't serve. */
|
|
63
|
+
onModuleInit(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Applies the migrations the schema hasn't had yet, whatever `migrate` says, in one transaction under an advisory
|
|
66
|
+
* lock: of processes that migrate together, one applies them. Resolves to the versions it applied (`[]`: none were
|
|
67
|
+
* pending).
|
|
68
|
+
*/
|
|
69
|
+
migrate(): Promise<number[]>;
|
|
70
|
+
create(instance: NewWorkflowInstance): Promise<{
|
|
71
|
+
instance: WorkflowInstance;
|
|
72
|
+
created: boolean;
|
|
73
|
+
}>;
|
|
74
|
+
/** `start(..., { transaction })`: the instance commits or rolls back with the application's rows. */
|
|
75
|
+
createInTransaction(transaction: unknown, instance: NewWorkflowInstance): Promise<{
|
|
76
|
+
instance: WorkflowInstance;
|
|
77
|
+
created: boolean;
|
|
78
|
+
}>;
|
|
79
|
+
get(id: string, options?: {
|
|
80
|
+
journal?: boolean;
|
|
81
|
+
}): Promise<WorkflowInstanceDetails | null>;
|
|
82
|
+
list(query: WorkflowListQuery): Promise<WorkflowInstance[]>;
|
|
83
|
+
requestCancel(id: string, { reason, now, terminate }: WorkflowCancelRequest): Promise<boolean>;
|
|
84
|
+
/** `WorkflowClient.retry()`: one conditional update, then the journal, in one transaction. */
|
|
85
|
+
reopen(id: string, reopen: WorkflowReopen): Promise<boolean>;
|
|
86
|
+
/** `WorkflowClient.delete()`: its journal and waits go with it (ON DELETE CASCADE). */
|
|
87
|
+
delete(id: string, statuses: WorkflowStatus[]): Promise<boolean>;
|
|
88
|
+
signal(signal: NewWorkflowSignal): Promise<WorkflowSignalResult>;
|
|
89
|
+
/** `signal(..., { transaction })`: the signal and its wake-ups commit with the application's rows. */
|
|
90
|
+
signalInTransaction(transaction: unknown, signal: NewWorkflowSignal): Promise<WorkflowSignalResult>;
|
|
91
|
+
signals(query: WorkflowSignalQuery): Promise<WorkflowSignalRecord[]>;
|
|
92
|
+
purge(query: WorkflowPurgeQuery): Promise<WorkflowPurgeResult>;
|
|
93
|
+
saveSchedule(save: WorkflowScheduleSave): Promise<WorkflowScheduleRecord | null>;
|
|
94
|
+
getSchedule(id: string): Promise<WorkflowScheduleRecord | null>;
|
|
95
|
+
listSchedules(query: WorkflowScheduleQuery): Promise<WorkflowScheduleRecord[]>;
|
|
96
|
+
deleteSchedule(id: string, revision?: number): Promise<boolean>;
|
|
97
|
+
claimSchedules(request: WorkflowScheduleClaimRequest): Promise<WorkflowScheduleRecord[]>;
|
|
98
|
+
writeSchedule(id: string, token: string, write: WorkflowScheduleWrite): Promise<boolean>;
|
|
99
|
+
claim(request: WorkflowClaimRequest): Promise<WorkflowClaim>;
|
|
100
|
+
/**
|
|
101
|
+
* A claim under concurrency or rate limits. Claims of a workflow with a concurrency limit take its lock first (in
|
|
102
|
+
* name order, so two claims never wait for each other's), so they count the slots live leases hold and lease the
|
|
103
|
+
* instances that fit one after the other: two never both take the last slot. Rate-limit windows are counted again
|
|
104
|
+
* under their rows' locks, once the instances are picked (see `takeRoom()`).
|
|
105
|
+
*/
|
|
106
|
+
private claimWithin;
|
|
107
|
+
/**
|
|
108
|
+
* Of `picked` (in claim order), the instances their rate-limit windows have room for, recorded in the windows. Each
|
|
109
|
+
* window's row is inserted or locked first, in a fixed order: the count read under the lock is exact (a concurrent
|
|
110
|
+
* claim of the same window waits for this one), and a purge can't delete the row in between.
|
|
111
|
+
*/
|
|
112
|
+
private takeRoom;
|
|
113
|
+
/** Leases the instances `due` (a subquery of `p`'s statement) selects and locks. */
|
|
114
|
+
private lease;
|
|
115
|
+
renew(id: string, token: string, leaseUntil: number): Promise<{
|
|
116
|
+
cancelRequested: boolean;
|
|
117
|
+
terminateRequested: boolean;
|
|
118
|
+
} | null>;
|
|
119
|
+
write(id: string, token: string, write: WorkflowWrite): Promise<boolean>;
|
|
120
|
+
private insertInstance;
|
|
121
|
+
private insertSignal;
|
|
122
|
+
/**
|
|
123
|
+
* Replaces the instance's waits, and says whether a signal committed after the execution read its cursor matches
|
|
124
|
+
* one of the new ones: then the instance stays due instead of losing it.
|
|
125
|
+
*/
|
|
126
|
+
private replaceWaits;
|
|
127
|
+
/** Journal entries by name: a new name goes last (`seq`), a known one is replaced in place. */
|
|
128
|
+
private upsertEntries;
|
|
129
|
+
/** Due, unleased instances of the versions the worker runs, as `alias` in a statement of `p`. */
|
|
130
|
+
private isDue;
|
|
131
|
+
private lastSignalId;
|
|
132
|
+
}
|