@sonamu-kit/tasks 0.2.0 → 0.3.0
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/.oxlintrc.json +3 -0
- package/AGENTS.md +21 -0
- package/dist/backend.d.ts +126 -107
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +4 -1
- package/dist/backend.js.map +1 -1
- package/dist/client.d.ts +145 -132
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +219 -213
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +15 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +22 -17
- package/dist/config.js.map +1 -1
- package/dist/core/duration.d.ts +5 -4
- package/dist/core/duration.d.ts.map +1 -1
- package/dist/core/duration.js +54 -59
- package/dist/core/duration.js.map +1 -1
- package/dist/core/error.d.ts +10 -7
- package/dist/core/error.d.ts.map +1 -1
- package/dist/core/error.js +21 -21
- package/dist/core/error.js.map +1 -1
- package/dist/core/json.d.ts +8 -3
- package/dist/core/json.d.ts.map +1 -1
- package/dist/core/result.d.ts +10 -14
- package/dist/core/result.d.ts.map +1 -1
- package/dist/core/result.js +21 -16
- package/dist/core/result.js.map +1 -1
- package/dist/core/retry.d.ts +37 -31
- package/dist/core/retry.d.ts.map +1 -1
- package/dist/core/retry.js +44 -51
- package/dist/core/retry.js.map +1 -1
- package/dist/core/schema.d.ts +57 -53
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/step.d.ts +28 -78
- package/dist/core/step.d.ts.map +1 -1
- package/dist/core/step.js +53 -63
- package/dist/core/step.js.map +1 -1
- package/dist/core/workflow.d.ts +33 -61
- package/dist/core/workflow.d.ts.map +1 -1
- package/dist/core/workflow.js +31 -41
- package/dist/core/workflow.js.map +1 -1
- package/dist/database/backend.d.ts +53 -46
- package/dist/database/backend.d.ts.map +1 -1
- package/dist/database/backend.js +544 -577
- package/dist/database/backend.js.map +1 -1
- package/dist/database/base.js +48 -25
- package/dist/database/base.js.map +1 -1
- package/dist/database/migrations/20251212000000_0_init.d.ts +10 -0
- package/dist/database/migrations/20251212000000_0_init.d.ts.map +1 -0
- package/dist/database/migrations/20251212000000_0_init.js +8 -4
- package/dist/database/migrations/20251212000000_0_init.js.map +1 -1
- package/dist/database/migrations/20251212000000_1_tables.d.ts +10 -0
- package/dist/database/migrations/20251212000000_1_tables.d.ts.map +1 -0
- package/dist/database/migrations/20251212000000_1_tables.js +81 -83
- package/dist/database/migrations/20251212000000_1_tables.js.map +1 -1
- package/dist/database/migrations/20251212000000_2_fk.d.ts +10 -0
- package/dist/database/migrations/20251212000000_2_fk.d.ts.map +1 -0
- package/dist/database/migrations/20251212000000_2_fk.js +20 -43
- package/dist/database/migrations/20251212000000_2_fk.js.map +1 -1
- package/dist/database/migrations/20251212000000_3_indexes.d.ts +10 -0
- package/dist/database/migrations/20251212000000_3_indexes.d.ts.map +1 -0
- package/dist/database/migrations/20251212000000_3_indexes.js +88 -102
- package/dist/database/migrations/20251212000000_3_indexes.js.map +1 -1
- package/dist/database/pubsub.d.ts +7 -16
- package/dist/database/pubsub.d.ts.map +1 -1
- package/dist/database/pubsub.js +75 -73
- package/dist/database/pubsub.js.map +1 -1
- package/dist/execution.d.ts +20 -59
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +175 -188
- package/dist/execution.js.map +1 -1
- package/dist/index.d.ts +5 -8
- package/dist/index.js +5 -5
- package/dist/internal.d.ts +12 -13
- package/dist/internal.js +4 -4
- package/dist/registry.d.ts +33 -27
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +58 -49
- package/dist/registry.js.map +1 -1
- package/dist/worker.d.ts +57 -50
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +194 -199
- package/dist/worker.js.map +1 -1
- package/dist/workflow.d.ts +26 -30
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +20 -15
- package/dist/workflow.js.map +1 -1
- package/nodemon.json +1 -1
- package/package.json +17 -19
- package/src/backend.ts +25 -9
- package/src/chaos.test.ts +3 -1
- package/src/client.test.ts +2 -0
- package/src/client.ts +30 -8
- package/src/config.test.ts +1 -0
- package/src/config.ts +3 -2
- package/src/core/duration.test.ts +2 -1
- package/src/core/duration.ts +1 -1
- package/src/core/error.test.ts +1 -0
- package/src/core/error.ts +1 -1
- package/src/core/result.test.ts +1 -0
- package/src/core/retry.test.ts +3 -2
- package/src/core/retry.ts +1 -1
- package/src/core/schema.ts +2 -2
- package/src/core/step.test.ts +2 -1
- package/src/core/step.ts +4 -3
- package/src/core/workflow.test.ts +2 -1
- package/src/core/workflow.ts +4 -3
- package/src/database/backend.test.ts +1 -0
- package/src/database/backend.testsuite.ts +44 -40
- package/src/database/backend.ts +207 -25
- package/src/database/base.test.ts +41 -0
- package/src/database/base.ts +51 -2
- package/src/database/migrations/20251212000000_0_init.ts +2 -1
- package/src/database/migrations/20251212000000_1_tables.ts +2 -1
- package/src/database/migrations/20251212000000_2_fk.ts +2 -1
- package/src/database/migrations/20251212000000_3_indexes.ts +2 -1
- package/src/database/pubsub.test.ts +6 -3
- package/src/database/pubsub.ts +55 -33
- package/src/execution.test.ts +2 -0
- package/src/execution.ts +49 -10
- package/src/internal.ts +15 -15
- package/src/practices/01-remote-workflow.ts +1 -0
- package/src/registry.test.ts +1 -0
- package/src/registry.ts +1 -1
- package/src/testing/connection.ts +3 -1
- package/src/worker.test.ts +2 -0
- package/src/worker.ts +30 -9
- package/src/workflow.test.ts +1 -0
- package/src/workflow.ts +3 -3
- package/templates/openworkflow.config.ts +2 -1
- package/tsdown.config.ts +31 -0
- package/.swcrc +0 -17
- package/dist/chaos.test.d.ts +0 -2
- package/dist/chaos.test.d.ts.map +0 -1
- package/dist/chaos.test.js +0 -92
- package/dist/chaos.test.js.map +0 -1
- package/dist/client.test.d.ts +0 -2
- package/dist/client.test.d.ts.map +0 -1
- package/dist/client.test.js +0 -340
- package/dist/client.test.js.map +0 -1
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -24
- package/dist/config.test.js.map +0 -1
- package/dist/core/duration.test.d.ts +0 -2
- package/dist/core/duration.test.d.ts.map +0 -1
- package/dist/core/duration.test.js +0 -265
- package/dist/core/duration.test.js.map +0 -1
- package/dist/core/error.test.d.ts +0 -2
- package/dist/core/error.test.d.ts.map +0 -1
- package/dist/core/error.test.js +0 -63
- package/dist/core/error.test.js.map +0 -1
- package/dist/core/json.js +0 -3
- package/dist/core/json.js.map +0 -1
- package/dist/core/result.test.d.ts +0 -2
- package/dist/core/result.test.d.ts.map +0 -1
- package/dist/core/result.test.js +0 -19
- package/dist/core/result.test.js.map +0 -1
- package/dist/core/retry.test.d.ts +0 -2
- package/dist/core/retry.test.d.ts.map +0 -1
- package/dist/core/retry.test.js +0 -198
- package/dist/core/retry.test.js.map +0 -1
- package/dist/core/schema.js +0 -4
- package/dist/core/schema.js.map +0 -1
- package/dist/core/step.test.d.ts +0 -2
- package/dist/core/step.test.d.ts.map +0 -1
- package/dist/core/step.test.js +0 -356
- package/dist/core/step.test.js.map +0 -1
- package/dist/core/workflow.test.d.ts +0 -2
- package/dist/core/workflow.test.d.ts.map +0 -1
- package/dist/core/workflow.test.js +0 -172
- package/dist/core/workflow.test.js.map +0 -1
- package/dist/database/backend.test.d.ts +0 -2
- package/dist/database/backend.test.d.ts.map +0 -1
- package/dist/database/backend.test.js +0 -19
- package/dist/database/backend.test.js.map +0 -1
- package/dist/database/backend.testsuite.d.ts +0 -20
- package/dist/database/backend.testsuite.d.ts.map +0 -1
- package/dist/database/backend.testsuite.js +0 -1280
- package/dist/database/backend.testsuite.js.map +0 -1
- package/dist/database/base.d.ts +0 -12
- package/dist/database/base.d.ts.map +0 -1
- package/dist/database/pubsub.test.d.ts +0 -2
- package/dist/database/pubsub.test.d.ts.map +0 -1
- package/dist/database/pubsub.test.js +0 -86
- package/dist/database/pubsub.test.js.map +0 -1
- package/dist/execution.test.d.ts +0 -2
- package/dist/execution.test.d.ts.map +0 -1
- package/dist/execution.test.js +0 -662
- package/dist/execution.test.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal.d.ts.map +0 -1
- package/dist/internal.js.map +0 -1
- package/dist/practices/01-remote-workflow.d.ts +0 -2
- package/dist/practices/01-remote-workflow.d.ts.map +0 -1
- package/dist/practices/01-remote-workflow.js +0 -70
- package/dist/practices/01-remote-workflow.js.map +0 -1
- package/dist/registry.test.d.ts +0 -2
- package/dist/registry.test.d.ts.map +0 -1
- package/dist/registry.test.js +0 -95
- package/dist/registry.test.js.map +0 -1
- package/dist/testing/connection.d.ts +0 -7
- package/dist/testing/connection.d.ts.map +0 -1
- package/dist/testing/connection.js +0 -39
- package/dist/testing/connection.js.map +0 -1
- package/dist/worker.test.d.ts +0 -2
- package/dist/worker.test.d.ts.map +0 -1
- package/dist/worker.test.js +0 -1164
- package/dist/worker.test.js.map +0 -1
- package/dist/workflow.test.d.ts +0 -2
- package/dist/workflow.test.d.ts.map +0 -1
- package/dist/workflow.test.js +0 -73
- package/dist/workflow.test.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/database/backend.ts"],"sourcesContent":["import { getLogger } from \"@logtape/logtape\";\nimport { camelize } from \"inflection\";\nimport knex, { type Knex } from \"knex\";\nimport {\n type Backend,\n type CancelWorkflowRunParams,\n type ClaimWorkflowRunParams,\n type CompleteStepAttemptParams,\n type CompleteWorkflowRunParams,\n type CreateStepAttemptParams,\n type CreateWorkflowRunParams,\n DEFAULT_NAMESPACE_ID,\n type ExtendWorkflowRunLeaseParams,\n type FailStepAttemptParams,\n type FailWorkflowRunParams,\n type GetStepAttemptParams,\n type GetWorkflowRunParams,\n type ListStepAttemptsParams,\n type ListWorkflowRunsParams,\n type PaginatedResponse,\n type SleepWorkflowRunParams,\n} from \"../backend\";\nimport { mergeRetryPolicy, type SerializableRetryPolicy } from \"../core/retry\";\nimport type { StepAttempt } from \"../core/step\";\nimport type { WorkflowRun } from \"../core/workflow\";\nimport { DEFAULT_SCHEMA, migrate } from \"./base\";\nimport { type OnSubscribed, PostgresPubSub } from \"./pubsub\";\n\nexport const DEFAULT_LISTEN_CHANNEL = \"new_tasks\" as const;\nconst DEFAULT_PAGINATION_PAGE_SIZE = 100 as const;\n\ninterface BackendPostgresOptions {\n namespaceId?: string;\n runMigrations?: boolean;\n\n // default: true\n usePubSub?: boolean;\n}\n\nconst logger = getLogger([\"sonamu\", \"internal\", \"tasks\"]);\nconst queryLogger = getLogger([\"sonamu\", \"internal\", \"tasks\", \"query\"]);\n\n/**\n * Manages a connection to a Postgres database for workflow operations.\n */\nexport class BackendPostgres implements Backend {\n private config: Knex.Config;\n private namespaceId: string;\n private usePubSub: boolean;\n private pubsub: PostgresPubSub | null = null;\n private initialized: boolean = false;\n private runMigrations: boolean;\n\n private _knex: Knex | null = null;\n private get knex(): Knex {\n if (!this._knex) {\n this._knex = knex(this.config);\n this._knex.on(\"query\", (query) => {\n queryLogger.debug(\"SQL: {query}, Values: {bindings}\", {\n query: query.sql,\n bindings: query.bindings,\n });\n });\n }\n\n return this._knex;\n }\n\n constructor(config: Knex.Config, options?: BackendPostgresOptions) {\n this.config = {\n ...config,\n postProcessResponse: (result, _queryContext) => {\n if (result === null || result === undefined) {\n return result;\n }\n\n if (config?.postProcessResponse) {\n result = config.postProcessResponse(result, _queryContext);\n }\n\n const camelizeRow = (row: Record<string, unknown>) =>\n Object.fromEntries(\n Object.entries(row).map(([key, value]) => [camelize(key, true), value]),\n );\n\n if (Array.isArray(result)) {\n return result.map(camelizeRow);\n }\n\n return camelizeRow(result);\n },\n };\n\n const { namespaceId, usePubSub, runMigrations } = {\n namespaceId: DEFAULT_NAMESPACE_ID,\n usePubSub: true,\n runMigrations: true,\n ...options,\n };\n\n this.namespaceId = namespaceId;\n this.usePubSub = usePubSub;\n this.runMigrations = runMigrations;\n }\n\n async initialize() {\n if (this.initialized) {\n return;\n }\n\n if (this.runMigrations) {\n await migrate(this.config, DEFAULT_SCHEMA);\n }\n\n this.initialized = true;\n }\n\n async subscribe(callback: OnSubscribed) {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n if (!this.usePubSub) {\n return;\n }\n\n if (!this.pubsub) {\n this.pubsub = await PostgresPubSub.create(this.knex);\n }\n\n this.pubsub.listenEvent(DEFAULT_LISTEN_CHANNEL, callback);\n }\n\n async publish(payload?: string): Promise<void> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n if (!this.usePubSub) {\n return;\n }\n\n await this.knex.raw(\n payload\n ? `NOTIFY ${DEFAULT_LISTEN_CHANNEL}, '${payload}'`\n : `NOTIFY ${DEFAULT_LISTEN_CHANNEL}`,\n );\n }\n\n async stop(): Promise<void> {\n if (!this.initialized) {\n return;\n }\n\n await this.pubsub?.destroy();\n this.pubsub = null;\n await this.knex.destroy();\n }\n\n async createWorkflowRun(params: CreateWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Creating workflow run: {workflowName}:{version}\", {\n workflowName: params.workflowName,\n version: params.version,\n });\n\n // config에 retryPolicy를 포함시킵니다.\n const configWithRetryPolicy = {\n ...(typeof params.config === \"object\" && params.config !== null ? params.config : {}),\n retryPolicy: params.retryPolicy ?? undefined,\n };\n\n const qb = this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .insert({\n namespace_id: this.namespaceId,\n id: crypto.randomUUID(),\n workflow_name: params.workflowName,\n version: params.version,\n status: \"pending\",\n idempotency_key: params.idempotencyKey,\n config: JSON.stringify(configWithRetryPolicy),\n context: params.context,\n input: params.input,\n attempts: 0,\n available_at: params.availableAt ?? this.knex.fn.now(),\n deadline_at: params.deadlineAt,\n created_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n const workflowRun = await qb;\n if (!workflowRun[0]) {\n logger.error(\"Failed to create workflow run: {params}\", { params });\n throw new Error(\"Failed to create workflow run\");\n }\n\n return workflowRun[0];\n }\n\n async getWorkflowRun(params: GetWorkflowRunParams): Promise<WorkflowRun | null> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Getting workflow run: {workflowRunId}\", { workflowRunId: params.workflowRunId });\n const workflowRun = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .select(\n \"namespace_id\",\n \"id\",\n \"workflow_name\",\n \"version\",\n \"status\",\n \"idempotency_key\",\n \"config\",\n \"context\",\n \"input\",\n \"output\",\n \"error\",\n \"attempts\",\n \"parent_step_attempt_namespace_id\",\n \"parent_step_attempt_id\",\n \"worker_id\",\n \"available_at\",\n \"deadline_at\",\n \"started_at\",\n \"finished_at\",\n \"created_at\",\n \"updated_at\",\n )\n .first();\n\n return workflowRun ?? null;\n }\n\n async listWorkflowRuns(params: ListWorkflowRunsParams): Promise<PaginatedResponse<WorkflowRun>> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Listing workflow runs: {after}, {before}\", {\n after: params.after,\n before: params.before,\n });\n const limit = params.limit ?? DEFAULT_PAGINATION_PAGE_SIZE;\n const { after, before } = params;\n\n let cursor: Cursor | null = null;\n if (after) {\n cursor = decodeCursor(after);\n } else if (before) {\n cursor = decodeCursor(before);\n }\n\n const qb = this.buildListWorkflowRunsWhere(params, cursor);\n const rows = await qb\n .orderBy(\"created_at\", before ? \"desc\" : \"asc\")\n .orderBy(\"id\", before ? \"desc\" : \"asc\")\n .limit(limit + 1);\n\n return this.processPaginationResults(\n rows,\n limit,\n typeof after === \"string\",\n typeof before === \"string\",\n );\n }\n\n private buildListWorkflowRunsWhere(params: ListWorkflowRunsParams, cursor: Cursor | null) {\n const { after } = params;\n const qb = this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId);\n\n if (cursor) {\n const operator = after ? \">\" : \"<\";\n return qb.whereRaw(`(\"created_at\", \"id\") ${operator} (?, ?)`, [\n cursor.createdAt.toISOString(),\n cursor.id,\n ]);\n }\n\n return qb;\n }\n\n async claimWorkflowRun(params: ClaimWorkflowRunParams): Promise<WorkflowRun | null> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Claiming workflow run: {workerId}, {leaseDurationMs}\", {\n workerId: params.workerId,\n leaseDurationMs: params.leaseDurationMs,\n });\n const claimed = await this.knex\n .with(\"expired\", (qb) =>\n qb\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .update({\n status: \"failed\",\n error: JSON.stringify({ message: \"Workflow run deadline exceeded\" }),\n worker_id: null,\n available_at: null,\n finished_at: this.knex.raw(\"NOW()\"),\n updated_at: this.knex.raw(\"NOW()\"),\n })\n .where(\"namespace_id\", this.namespaceId)\n .whereIn(\"status\", [\"pending\", \"running\", \"sleeping\"])\n .whereNotNull(\"deadline_at\")\n .where(\"deadline_at\", \"<=\", this.knex.raw(\"NOW()\"))\n .returning(\"id\"),\n )\n .with(\"candidate\", (qb) =>\n qb\n .withSchema(DEFAULT_SCHEMA)\n .select(\"id\")\n .from(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .whereIn(\"status\", [\"pending\", \"running\", \"sleeping\"])\n .where(\"available_at\", \"<=\", this.knex.raw(\"NOW()\"))\n .where((qb2) => {\n qb2.whereNull(\"deadline_at\").orWhere(\"deadline_at\", \">\", this.knex.raw(\"NOW()\"));\n })\n .orderByRaw(\"CASE WHEN status = 'pending' THEN 0 ELSE 1 END\")\n .orderBy(\"available_at\", \"asc\")\n .orderBy(\"created_at\", \"asc\")\n .limit(1)\n .forUpdate()\n .skipLocked(),\n )\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs as wr\")\n .where(\"wr.namespace_id\", this.namespaceId)\n .where(\"wr.id\", this.knex.ref(\"candidate.id\"))\n .update({\n status: \"running\",\n attempts: this.knex.raw(\"wr.attempts + 1\"),\n worker_id: params.workerId,\n available_at: this.knex.raw(`NOW() + ${params.leaseDurationMs} * INTERVAL '1 millisecond'`),\n started_at: this.knex.raw(\"COALESCE(wr.started_at, NOW())\"),\n updated_at: this.knex.raw(\"NOW()\"),\n })\n .updateFrom(\"candidate\")\n .returning(\"wr.*\");\n\n return claimed[0] ?? null;\n }\n\n async extendWorkflowRunLease(params: ExtendWorkflowRunLeaseParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Extending workflow run lease: {workflowRunId}, {workerId}, {leaseDurationMs}\", {\n workflowRunId: params.workflowRunId,\n workerId: params.workerId,\n leaseDurationMs: params.leaseDurationMs,\n });\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .where(\"status\", \"running\")\n .where(\"worker_id\", params.workerId)\n .update({\n available_at: this.knex.raw(`NOW() + ${params.leaseDurationMs} * INTERVAL '1 millisecond'`),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to extend lease for workflow run: {params}\", { params });\n throw new Error(\"Failed to extend lease for workflow run\");\n }\n\n return updated;\n }\n\n async sleepWorkflowRun(params: SleepWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Sleeping workflow run: {workflowRunId}, {workerId}, {availableAt}\", {\n workflowRunId: params.workflowRunId,\n workerId: params.workerId,\n availableAt: params.availableAt,\n });\n\n // 'succeeded' status is deprecated\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .whereNotIn(\"status\", [\"succeeded\", \"completed\", \"failed\", \"canceled\"])\n .where(\"worker_id\", params.workerId)\n .update({\n status: \"sleeping\",\n available_at: params.availableAt,\n worker_id: null,\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to sleep workflow run: {params}\", { params });\n throw new Error(\"Failed to sleep workflow run\");\n }\n\n return updated;\n }\n\n async completeWorkflowRun(params: CompleteWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Completing workflow run: {workflowRunId}, {workerId}, {output}\", {\n workflowRunId: params.workflowRunId,\n workerId: params.workerId,\n output: params.output,\n });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .where(\"status\", \"running\")\n .where(\"worker_id\", params.workerId)\n .update({\n status: \"completed\",\n output: JSON.stringify(params.output),\n error: null,\n worker_id: params.workerId,\n available_at: null,\n finished_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to complete workflow run: {params}\", { params });\n throw new Error(\"Failed to complete workflow run\");\n }\n\n return updated;\n }\n\n async failWorkflowRun(params: FailWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n const { workflowRunId, error, forceComplete, customDelayMs } = params;\n\n logger.info(\"Failing workflow run: {workflowRunId}, {workerId}, {error}\", {\n workflowRunId: params.workflowRunId,\n workerId: params.workerId,\n error: params.error,\n });\n\n const workflowRun = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", workflowRunId)\n .first();\n\n if (!workflowRun) {\n throw new Error(\"Workflow run not found\");\n }\n\n const config =\n typeof workflowRun.config === \"string\" ? JSON.parse(workflowRun.config) : workflowRun.config;\n const savedRetryPolicy: SerializableRetryPolicy | undefined = config?.retryPolicy;\n const retryPolicy = mergeRetryPolicy(savedRetryPolicy);\n\n const { initialIntervalMs, backoffCoefficient, maximumIntervalMs, maxAttempts } = retryPolicy;\n\n const currentAttempts = workflowRun.attempts ?? 0;\n const shouldForceComplete = forceComplete || currentAttempts >= maxAttempts;\n\n if (shouldForceComplete) {\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", workflowRunId)\n .where(\"status\", \"running\")\n .where(\"worker_id\", params.workerId)\n .update({\n status: \"failed\",\n available_at: null,\n finished_at: this.knex.fn.now(),\n error: JSON.stringify(error),\n worker_id: null,\n started_at: null,\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to mark workflow run failed: {params}\", { params });\n throw new Error(\"Failed to mark workflow run failed\");\n }\n return updated;\n }\n\n // this beefy query updates a workflow's status, available_at, and\n // finished_at based on the workflow's deadline and retry policy\n //\n // if the next retry would exceed the deadline, the run is marked as\n // 'failed' and finalized, otherwise, the run is rescheduled with an updated\n // 'available_at' timestamp for the next retry\n const retryIntervalExpr = customDelayMs\n ? `${customDelayMs} * INTERVAL '1 millisecond'`\n : `LEAST(${initialIntervalMs} * POWER(${backoffCoefficient}, \"attempts\" - 1), ${maximumIntervalMs}) * INTERVAL '1 millisecond'`;\n const deadlineExceededCondition = `\"deadline_at\" IS NOT NULL AND NOW() + (${retryIntervalExpr}) >= \"deadline_at\"`;\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", workflowRunId)\n .where(\"status\", \"running\")\n .where(\"worker_id\", params.workerId)\n .update({\n status: this.knex.raw(\n `CASE WHEN ${deadlineExceededCondition} THEN 'failed' ELSE 'pending' END`,\n ),\n available_at: this.knex.raw(\n `CASE WHEN ${deadlineExceededCondition} THEN NULL ELSE NOW() + (${retryIntervalExpr}) END`,\n ),\n finished_at: this.knex.raw(\n `CASE WHEN ${deadlineExceededCondition} THEN NOW() ELSE NULL END`,\n ),\n error: JSON.stringify(error),\n worker_id: null,\n started_at: null,\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to mark workflow run failed: {params}\", { params });\n throw new Error(\"Failed to mark workflow run failed\");\n }\n\n return updated;\n }\n\n async cancelWorkflowRun(params: CancelWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Canceling workflow run: {workflowRunId}\", { workflowRunId: params.workflowRunId });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .whereIn(\"status\", [\"pending\", \"running\", \"sleeping\"])\n .update({\n status: \"canceled\",\n worker_id: null,\n available_at: null,\n finished_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n // workflow may already be in a terminal state\n const existing = await this.getWorkflowRun({\n workflowRunId: params.workflowRunId,\n });\n if (!existing) {\n throw new Error(`Workflow run ${params.workflowRunId} does not exist`);\n }\n\n // if already canceled, just return it\n if (existing.status === \"canceled\") {\n return existing;\n }\n\n // throw error for completed/failed workflows\n // 'succeeded' status is deprecated\n if ([\"succeeded\", \"completed\", \"failed\"].includes(existing.status)) {\n logger.error(\"Cannot cancel workflow run: {params} with status {status}\", {\n params,\n status: existing.status,\n });\n throw new Error(\n `Cannot cancel workflow run ${params.workflowRunId} with status ${existing.status}`,\n );\n }\n\n logger.error(\"Failed to cancel workflow run: {params}\", { params });\n throw new Error(\"Failed to cancel workflow run\");\n }\n\n return updated;\n }\n\n async createStepAttempt(params: CreateStepAttemptParams): Promise<StepAttempt> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Creating step attempt: {workflowRunId}, {stepName}, {kind}\", {\n workflowRunId: params.workflowRunId,\n stepName: params.stepName,\n kind: params.kind,\n });\n\n const [stepAttempt] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts\")\n .insert({\n namespace_id: this.namespaceId,\n id: crypto.randomUUID(),\n workflow_run_id: params.workflowRunId,\n step_name: params.stepName,\n kind: params.kind,\n status: \"running\",\n config: JSON.stringify(params.config),\n context: JSON.stringify(params.context),\n started_at: this.knex.fn.now(),\n created_at: this.knex.raw(\"date_trunc('milliseconds', NOW())\"),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!stepAttempt) {\n logger.error(\"Failed to create step attempt: {params}\", { params });\n throw new Error(\"Failed to create step attempt\");\n }\n\n return stepAttempt;\n }\n\n async getStepAttempt(params: GetStepAttemptParams): Promise<StepAttempt | null> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Getting step attempt: {stepAttemptId}\", { stepAttemptId: params.stepAttemptId });\n\n const stepAttempt = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.stepAttemptId)\n .first();\n\n return stepAttempt ?? null;\n }\n\n async listStepAttempts(params: ListStepAttemptsParams): Promise<PaginatedResponse<StepAttempt>> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Listing step attempts: {workflowRunId}, {after}, {before}\", {\n workflowRunId: params.workflowRunId,\n after: params.after,\n before: params.before,\n });\n\n const limit = params.limit ?? DEFAULT_PAGINATION_PAGE_SIZE;\n const { after, before } = params;\n\n let cursor: Cursor | null = null;\n if (after) {\n cursor = decodeCursor(after);\n } else if (before) {\n cursor = decodeCursor(before);\n }\n\n const qb = this.buildListStepAttemptsWhere(params, cursor);\n const rows = await qb\n .orderBy(\"created_at\", before ? \"desc\" : \"asc\")\n .orderBy(\"id\", before ? \"desc\" : \"asc\")\n .limit(limit + 1);\n\n return this.processPaginationResults(\n rows,\n limit,\n typeof after === \"string\",\n typeof before === \"string\",\n );\n }\n\n private buildListStepAttemptsWhere(params: ListStepAttemptsParams, cursor: Cursor | null) {\n const { after } = params;\n const qb = this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"workflow_run_id\", params.workflowRunId);\n\n if (cursor) {\n const operator = after ? \">\" : \"<\";\n return qb.whereRaw(`(\"created_at\", \"id\") ${operator} (?, ?)`, [\n cursor.createdAt.toISOString(),\n cursor.id,\n ]);\n }\n\n return qb;\n }\n\n private processPaginationResults<T extends Cursor>(\n rows: T[],\n limit: number,\n hasAfter: boolean,\n hasBefore: boolean,\n ): PaginatedResponse<T> {\n const data = rows;\n let hasNext = false;\n let hasPrev = false;\n\n if (hasBefore) {\n data.reverse();\n if (data.length > limit) {\n hasPrev = true;\n data.shift();\n }\n hasNext = true;\n } else {\n if (data.length > limit) {\n hasNext = true;\n data.pop();\n }\n if (hasAfter) {\n hasPrev = true;\n }\n }\n\n const lastItem = data.at(-1);\n const nextCursor = hasNext && lastItem ? encodeCursor(lastItem) : null;\n const firstItem = data[0];\n const prevCursor = hasPrev && firstItem ? encodeCursor(firstItem) : null;\n\n return {\n data,\n pagination: {\n next: nextCursor,\n prev: prevCursor,\n },\n };\n }\n\n // NOTE: 실제 서비스에서 이게 안 되는 것 같은데, 쿼리 등을 체크할 필요가 있음.\n async completeStepAttempt(params: CompleteStepAttemptParams): Promise<StepAttempt> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Marking step attempt as completed: {workflowRunId}, {stepAttemptId}, {workerId}\", {\n workflowRunId: params.workflowRunId,\n stepAttemptId: params.stepAttemptId,\n workerId: params.workerId,\n });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts as sa\")\n .update({\n status: \"completed\",\n output: JSON.stringify(params.output),\n error: null,\n finished_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .updateFrom(`${DEFAULT_SCHEMA}.workflow_runs as wr`)\n .where(\"sa.namespace_id\", this.namespaceId)\n .where(\"sa.workflow_run_id\", params.workflowRunId)\n .where(\"sa.id\", params.stepAttemptId)\n .where(\"sa.status\", \"running\")\n .where(\"wr.namespace_id\", this.knex.ref(\"sa.namespace_id\"))\n .where(\"wr.id\", this.knex.ref(\"sa.workflow_run_id\"))\n .where(\"wr.status\", \"running\")\n .where(\"wr.worker_id\", params.workerId)\n .returning(\"sa.*\");\n\n if (!updated) {\n logger.error(\"Failed to mark step attempt completed: {params}\", { params });\n throw new Error(\"Failed to mark step attempt completed\");\n }\n\n return updated;\n }\n\n async failStepAttempt(params: FailStepAttemptParams): Promise<StepAttempt> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Marking step attempt as failed: {workflowRunId}, {stepAttemptId}, {workerId}\", {\n workflowRunId: params.workflowRunId,\n stepAttemptId: params.stepAttemptId,\n workerId: params.workerId,\n });\n logger.info(\"Error: {error.message}\", { error: params.error.message });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts as sa\")\n .update({\n status: \"failed\",\n output: null,\n error: JSON.stringify(params.error),\n finished_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .updateFrom(`${DEFAULT_SCHEMA}.workflow_runs as wr`)\n .where(\"sa.namespace_id\", this.namespaceId)\n .where(\"sa.workflow_run_id\", params.workflowRunId)\n .where(\"sa.id\", params.stepAttemptId)\n .where(\"sa.status\", \"running\")\n .where(\"wr.namespace_id\", this.knex.ref(\"sa.namespace_id\"))\n .where(\"wr.id\", this.knex.ref(\"sa.workflow_run_id\"))\n .where(\"wr.status\", \"running\")\n .where(\"wr.worker_id\", params.workerId)\n .returning(\"sa.*\");\n\n if (!updated) {\n logger.error(\"Failed to mark step attempt failed: {params}\", { params });\n throw new Error(\"Failed to mark step attempt failed\");\n }\n\n return updated;\n }\n}\n\n/**\n * Cursor used for pagination. Requires created_at and id fields. Because JS\n * Date does not natively support microsecond precision dates, created_at should\n * be stored with millisecond precision in paginated tables to avoid issues with\n * cursor comparisons.\n */\ninterface Cursor {\n createdAt: Date;\n id: string;\n}\n\nfunction encodeCursor(item: Cursor): string {\n const encoded = Buffer.from(\n JSON.stringify({ createdAt: item.createdAt.toISOString(), id: item.id }),\n ).toString(\"base64\");\n return encoded;\n}\n\nexport function decodeCursor(cursor: string): Cursor {\n const decoded = Buffer.from(cursor, \"base64\").toString(\"utf8\");\n const parsed = JSON.parse(decoded) as { createdAt: string; id: string };\n return {\n createdAt: new Date(parsed.createdAt),\n id: parsed.id,\n };\n}\n"],"names":["getLogger","camelize","knex","DEFAULT_NAMESPACE_ID","mergeRetryPolicy","DEFAULT_SCHEMA","migrate","PostgresPubSub","DEFAULT_LISTEN_CHANNEL","DEFAULT_PAGINATION_PAGE_SIZE","logger","queryLogger","BackendPostgres","config","namespaceId","usePubSub","pubsub","initialized","runMigrations","_knex","on","query","debug","sql","bindings","options","postProcessResponse","result","_queryContext","undefined","camelizeRow","row","Object","fromEntries","entries","map","key","value","Array","isArray","initialize","subscribe","callback","Error","create","listenEvent","publish","payload","raw","stop","destroy","createWorkflowRun","params","info","workflowName","version","configWithRetryPolicy","retryPolicy","qb","withSchema","table","insert","namespace_id","id","crypto","randomUUID","workflow_name","status","idempotency_key","idempotencyKey","JSON","stringify","context","input","attempts","available_at","availableAt","fn","now","deadline_at","deadlineAt","created_at","updated_at","returning","workflowRun","error","getWorkflowRun","workflowRunId","where","select","first","listWorkflowRuns","after","before","limit","cursor","decodeCursor","buildListWorkflowRunsWhere","rows","orderBy","processPaginationResults","operator","whereRaw","createdAt","toISOString","claimWorkflowRun","workerId","leaseDurationMs","claimed","with","update","message","worker_id","finished_at","whereIn","whereNotNull","from","qb2","whereNull","orWhere","orderByRaw","forUpdate","skipLocked","ref","started_at","updateFrom","extendWorkflowRunLease","updated","sleepWorkflowRun","whereNotIn","completeWorkflowRun","output","failWorkflowRun","forceComplete","customDelayMs","parse","savedRetryPolicy","initialIntervalMs","backoffCoefficient","maximumIntervalMs","maxAttempts","currentAttempts","shouldForceComplete","retryIntervalExpr","deadlineExceededCondition","cancelWorkflowRun","existing","includes","createStepAttempt","stepName","kind","stepAttempt","workflow_run_id","step_name","getStepAttempt","stepAttemptId","listStepAttempts","buildListStepAttemptsWhere","hasAfter","hasBefore","data","hasNext","hasPrev","reverse","length","shift","pop","lastItem","at","nextCursor","encodeCursor","firstItem","prevCursor","pagination","next","prev","completeStepAttempt","failStepAttempt","item","encoded","Buffer","toString","decoded","parsed","Date"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"backend.js","names":["cursor: Cursor | null","savedRetryPolicy: SerializableRetryPolicy | undefined","updated"],"sources":["../../src/database/backend.ts"],"sourcesContent":["import { getLogger } from \"@logtape/logtape\";\nimport { camelize } from \"inflection\";\nimport knex from \"knex\";\nimport { type Knex } from \"knex\";\n\nimport { DEFAULT_NAMESPACE_ID } from \"../backend\";\nimport {\n type Backend,\n type CancelWorkflowRunParams,\n type ClaimWorkflowRunParams,\n type CompleteStepAttemptParams,\n type CompleteWorkflowRunParams,\n type CreateStepAttemptParams,\n type CreateWorkflowRunParams,\n type ExtendWorkflowRunLeaseParams,\n type FailStepAttemptParams,\n type FailWorkflowRunParams,\n type GetStepAttemptParams,\n type GetWorkflowRunParams,\n type ListStepAttemptsParams,\n type ListWorkflowRunsParams,\n type PaginatedResponse,\n type PauseWorkflowRunParams,\n type ResumeWorkflowRunParams,\n type SleepWorkflowRunParams,\n} from \"../backend\";\nimport { mergeRetryPolicy } from \"../core/retry\";\nimport { type SerializableRetryPolicy } from \"../core/retry\";\nimport { type StepAttempt } from \"../core/step\";\nimport { type WorkflowRun } from \"../core/workflow\";\nimport { DEFAULT_SCHEMA, migrate } from \"./base\";\nimport { PostgresPubSub } from \"./pubsub\";\nimport { type OnSubscribed } from \"./pubsub\";\n\nexport const DEFAULT_LISTEN_CHANNEL = \"new_tasks\" as const;\nconst DEFAULT_PAGINATION_PAGE_SIZE = 100 as const;\n\ninterface BackendPostgresOptions {\n namespaceId?: string;\n runMigrations?: boolean;\n\n // default: true\n usePubSub?: boolean;\n}\n\nconst logger = getLogger([\"sonamu\", \"internal\", \"tasks\"]);\nconst queryLogger = getLogger([\"sonamu\", \"internal\", \"tasks\", \"query\"]);\n\n/**\n * Manages a connection to a Postgres database for workflow operations.\n */\nexport class BackendPostgres implements Backend {\n private config: Knex.Config;\n private namespaceId: string;\n private usePubSub: boolean;\n private pubsub: PostgresPubSub | null = null;\n private initialized: boolean = false;\n private runMigrations: boolean;\n\n private _knex: Knex | null = null;\n private get knex(): Knex {\n if (!this._knex) {\n this._knex = knex(this.config);\n this._knex.on(\"query\", (query) => {\n queryLogger.debug(\"SQL: {query}, Values: {bindings}\", {\n query: query.sql,\n bindings: query.bindings,\n });\n });\n }\n\n return this._knex;\n }\n\n constructor(config: Knex.Config, options?: BackendPostgresOptions) {\n this.config = {\n ...config,\n postProcessResponse: (result, _queryContext) => {\n if (result === null || result === undefined) {\n return result;\n }\n\n if (config?.postProcessResponse) {\n result = config.postProcessResponse(result, _queryContext);\n }\n\n const camelizeRow = (row: Record<string, unknown>) =>\n Object.fromEntries(\n Object.entries(row).map(([key, value]) => [camelize(key, true), value]),\n );\n\n if (Array.isArray(result)) {\n return result.map(camelizeRow);\n }\n\n return camelizeRow(result);\n },\n };\n\n const { namespaceId, usePubSub, runMigrations } = {\n namespaceId: DEFAULT_NAMESPACE_ID,\n usePubSub: true,\n runMigrations: true,\n ...options,\n };\n\n this.namespaceId = namespaceId;\n this.usePubSub = usePubSub;\n this.runMigrations = runMigrations;\n }\n\n async initialize() {\n if (this.initialized) {\n return;\n }\n\n if (this.runMigrations) {\n await migrate(this.config, DEFAULT_SCHEMA);\n }\n\n this.initialized = true;\n }\n\n async subscribe(callback: OnSubscribed) {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n if (!this.usePubSub) {\n return;\n }\n\n if (!this.pubsub) {\n this.pubsub = await PostgresPubSub.create(this.knex);\n }\n\n this.pubsub.listenEvent(DEFAULT_LISTEN_CHANNEL, callback);\n }\n\n async publish(payload?: string): Promise<void> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n if (!this.usePubSub) {\n return;\n }\n\n await this.knex.raw(\n payload\n ? `NOTIFY ${DEFAULT_LISTEN_CHANNEL}, '${payload}'`\n : `NOTIFY ${DEFAULT_LISTEN_CHANNEL}`,\n );\n }\n\n async stop(): Promise<void> {\n if (!this.initialized) {\n return;\n }\n\n await this.pubsub?.destroy();\n this.pubsub = null;\n await this.knex.destroy();\n this._knex = null;\n this.initialized = false;\n }\n\n async createWorkflowRun(params: CreateWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Creating workflow run: {workflowName}:{version}\", {\n workflowName: params.workflowName,\n version: params.version,\n });\n\n // config에 retryPolicy를 포함시킵니다.\n const configWithRetryPolicy = {\n ...(typeof params.config === \"object\" && params.config !== null ? params.config : {}),\n retryPolicy: params.retryPolicy ?? undefined,\n };\n\n const qb = this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .insert({\n namespace_id: this.namespaceId,\n id: crypto.randomUUID(),\n workflow_name: params.workflowName,\n version: params.version,\n status: \"pending\",\n idempotency_key: params.idempotencyKey,\n config: JSON.stringify(configWithRetryPolicy),\n context: params.context,\n input: params.input,\n attempts: 0,\n available_at: params.availableAt ?? this.knex.fn.now(),\n deadline_at: params.deadlineAt,\n created_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n const workflowRun = await qb;\n if (!workflowRun[0]) {\n logger.error(\"Failed to create workflow run: {params}\", { params });\n throw new Error(\"Failed to create workflow run\");\n }\n\n return workflowRun[0];\n }\n\n async getWorkflowRun(params: GetWorkflowRunParams): Promise<WorkflowRun | null> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Getting workflow run: {workflowRunId}\", { workflowRunId: params.workflowRunId });\n const workflowRun = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .select(\n \"namespace_id\",\n \"id\",\n \"workflow_name\",\n \"version\",\n \"status\",\n \"idempotency_key\",\n \"config\",\n \"context\",\n \"input\",\n \"output\",\n \"error\",\n \"attempts\",\n \"parent_step_attempt_namespace_id\",\n \"parent_step_attempt_id\",\n \"worker_id\",\n \"available_at\",\n \"deadline_at\",\n \"started_at\",\n \"finished_at\",\n \"created_at\",\n \"updated_at\",\n )\n .first();\n\n return workflowRun ?? null;\n }\n\n async listWorkflowRuns(params: ListWorkflowRunsParams): Promise<PaginatedResponse<WorkflowRun>> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Listing workflow runs: {after}, {before}\", {\n after: params.after,\n before: params.before,\n });\n const limit = params.limit ?? DEFAULT_PAGINATION_PAGE_SIZE;\n const { after, before } = params;\n const order = params.order ?? \"asc\";\n const reverseOrder = order === \"asc\" ? \"desc\" : \"asc\";\n\n let cursor: Cursor | null = null;\n if (after) {\n cursor = decodeCursor(after);\n } else if (before) {\n cursor = decodeCursor(before);\n }\n\n const qb = this.buildListWorkflowRunsWhere(params, cursor, order);\n const rows = await qb\n .orderBy(\"created_at\", before ? reverseOrder : order)\n .orderBy(\"id\", before ? reverseOrder : order)\n .limit(limit + 1);\n\n return this.processPaginationResults(\n rows,\n limit,\n typeof after === \"string\",\n typeof before === \"string\",\n );\n }\n\n private buildListWorkflowRunsWhere(\n params: ListWorkflowRunsParams,\n cursor: Cursor | null,\n order: \"asc\" | \"desc\",\n ) {\n const { after } = params;\n const qb = this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId);\n\n if (cursor) {\n // asc: after → \">\", before → \"<\"\n // desc: after → \"<\", before → \">\"\n const operator = (order === \"asc\") === !!after ? \">\" : \"<\";\n qb.whereRaw(`(\"created_at\", \"id\") ${operator} (?, ?)`, [\n cursor.createdAt.toISOString(),\n cursor.id,\n ]);\n }\n\n if (params.status && params.status.length > 0) {\n qb.whereIn(\"status\", params.status);\n }\n if (params.workflowName) {\n qb.where(\"workflow_name\", params.workflowName);\n }\n if (params.createdAfter) {\n qb.where(\"created_at\", \">=\", params.createdAfter);\n }\n if (params.createdBefore) {\n qb.where(\"created_at\", \"<=\", params.createdBefore);\n }\n\n return qb;\n }\n\n async claimWorkflowRun(params: ClaimWorkflowRunParams): Promise<WorkflowRun | null> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Claiming workflow run: {workerId}, {leaseDurationMs}\", {\n workerId: params.workerId,\n leaseDurationMs: params.leaseDurationMs,\n });\n const claimed = await this.knex\n .with(\"expired\", (qb) =>\n qb\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .update({\n status: \"failed\",\n error: JSON.stringify({ message: \"Workflow run deadline exceeded\" }),\n worker_id: null,\n available_at: null,\n finished_at: this.knex.raw(\"NOW()\"),\n updated_at: this.knex.raw(\"NOW()\"),\n })\n .where(\"namespace_id\", this.namespaceId)\n .whereIn(\"status\", [\"pending\", \"running\", \"sleeping\"])\n .whereNotNull(\"deadline_at\")\n .where(\"deadline_at\", \"<=\", this.knex.raw(\"NOW()\"))\n .returning(\"id\"),\n )\n .with(\"candidate\", (qb) =>\n qb\n .withSchema(DEFAULT_SCHEMA)\n .select(\"id\")\n .from(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .whereIn(\"status\", [\"pending\", \"running\", \"sleeping\"])\n .where(\"available_at\", \"<=\", this.knex.raw(\"NOW()\"))\n .where((qb2) => {\n qb2.whereNull(\"deadline_at\").orWhere(\"deadline_at\", \">\", this.knex.raw(\"NOW()\"));\n })\n .orderByRaw(\"CASE WHEN status = 'pending' THEN 0 ELSE 1 END\")\n .orderBy(\"available_at\", \"asc\")\n .orderBy(\"created_at\", \"asc\")\n .limit(1)\n .forUpdate()\n .skipLocked(),\n )\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs as wr\")\n .where(\"wr.namespace_id\", this.namespaceId)\n .where(\"wr.id\", this.knex.ref(\"candidate.id\"))\n .update({\n status: \"running\",\n attempts: this.knex.raw(\"wr.attempts + 1\"),\n worker_id: params.workerId,\n available_at: this.knex.raw(`NOW() + ${params.leaseDurationMs} * INTERVAL '1 millisecond'`),\n started_at: this.knex.raw(\"COALESCE(wr.started_at, NOW())\"),\n updated_at: this.knex.raw(\"NOW()\"),\n })\n .updateFrom(\"candidate\")\n .returning(\"wr.*\");\n\n return claimed[0] ?? null;\n }\n\n async extendWorkflowRunLease(params: ExtendWorkflowRunLeaseParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Extending workflow run lease: {workflowRunId}, {workerId}, {leaseDurationMs}\", {\n workflowRunId: params.workflowRunId,\n workerId: params.workerId,\n leaseDurationMs: params.leaseDurationMs,\n });\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .where(\"status\", \"running\")\n .where(\"worker_id\", params.workerId)\n .update({\n available_at: this.knex.raw(`NOW() + ${params.leaseDurationMs} * INTERVAL '1 millisecond'`),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n const wr = await this.getWorkflowRun({ workflowRunId: params.workflowRunId });\n if (wr && (wr.status === \"paused\" || wr.status === \"canceled\")) {\n throw new Error(\"Workflow run is paused or canceled\");\n }\n\n logger.error(\"Failed to extend lease for workflow run: {params}\", { params });\n throw new Error(\"Failed to extend lease for workflow run\");\n }\n\n return updated;\n }\n\n async sleepWorkflowRun(params: SleepWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Sleeping workflow run: {workflowRunId}, {workerId}, {availableAt}\", {\n workflowRunId: params.workflowRunId,\n workerId: params.workerId,\n availableAt: params.availableAt,\n });\n\n // 'succeeded' status is deprecated\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .whereNotIn(\"status\", [\"succeeded\", \"completed\", \"failed\", \"canceled\"])\n .where(\"worker_id\", params.workerId)\n .update({\n status: \"sleeping\",\n available_at: params.availableAt,\n worker_id: null,\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to sleep workflow run: {params}\", { params });\n throw new Error(\"Failed to sleep workflow run\");\n }\n\n return updated;\n }\n\n async completeWorkflowRun(params: CompleteWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Completing workflow run: {workflowRunId}, {workerId}, {output}\", {\n workflowRunId: params.workflowRunId,\n workerId: params.workerId,\n output: params.output,\n });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .where(\"status\", \"running\")\n .where(\"worker_id\", params.workerId)\n .update({\n status: \"completed\",\n output: JSON.stringify(params.output),\n error: null,\n worker_id: params.workerId,\n available_at: null,\n finished_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to complete workflow run: {params}\", { params });\n throw new Error(\"Failed to complete workflow run\");\n }\n\n return updated;\n }\n\n async failWorkflowRun(params: FailWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n const { workflowRunId, error, forceComplete, customDelayMs } = params;\n\n logger.info(\"Failing workflow run: {workflowRunId}, {workerId}, {error}\", {\n workflowRunId: params.workflowRunId,\n workerId: params.workerId,\n error: params.error,\n });\n\n const workflowRun = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", workflowRunId)\n .first();\n\n if (!workflowRun) {\n throw new Error(\"Workflow run not found\");\n }\n\n const config =\n typeof workflowRun.config === \"string\" ? JSON.parse(workflowRun.config) : workflowRun.config;\n const savedRetryPolicy: SerializableRetryPolicy | undefined = config?.retryPolicy;\n const retryPolicy = mergeRetryPolicy(savedRetryPolicy);\n\n const { initialIntervalMs, backoffCoefficient, maximumIntervalMs, maxAttempts } = retryPolicy;\n\n const currentAttempts = workflowRun.attempts ?? 0;\n const shouldForceComplete = forceComplete || currentAttempts >= maxAttempts;\n\n if (shouldForceComplete) {\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", workflowRunId)\n .where(\"status\", \"running\")\n .where(\"worker_id\", params.workerId)\n .update({\n status: \"failed\",\n available_at: null,\n finished_at: this.knex.fn.now(),\n error: JSON.stringify(error),\n worker_id: null,\n started_at: null,\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to mark workflow run failed: {params}\", { params });\n throw new Error(\"Failed to mark workflow run failed\");\n }\n return updated;\n }\n\n // this beefy query updates a workflow's status, available_at, and\n // finished_at based on the workflow's deadline and retry policy\n //\n // if the next retry would exceed the deadline, the run is marked as\n // 'failed' and finalized, otherwise, the run is rescheduled with an updated\n // 'available_at' timestamp for the next retry\n const retryIntervalExpr = customDelayMs\n ? `${customDelayMs} * INTERVAL '1 millisecond'`\n : `LEAST(${initialIntervalMs} * POWER(${backoffCoefficient}, \"attempts\" - 1), ${maximumIntervalMs}) * INTERVAL '1 millisecond'`;\n const deadlineExceededCondition = `\"deadline_at\" IS NOT NULL AND NOW() + (${retryIntervalExpr}) >= \"deadline_at\"`;\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", workflowRunId)\n .where(\"status\", \"running\")\n .where(\"worker_id\", params.workerId)\n .update({\n status: this.knex.raw(\n `CASE WHEN ${deadlineExceededCondition} THEN 'failed' ELSE 'pending' END`,\n ),\n available_at: this.knex.raw(\n `CASE WHEN ${deadlineExceededCondition} THEN NULL ELSE NOW() + (${retryIntervalExpr}) END`,\n ),\n finished_at: this.knex.raw(\n `CASE WHEN ${deadlineExceededCondition} THEN NOW() ELSE NULL END`,\n ),\n error: JSON.stringify(error),\n worker_id: null,\n started_at: null,\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n logger.error(\"Failed to mark workflow run failed: {params}\", { params });\n throw new Error(\"Failed to mark workflow run failed\");\n }\n\n return updated;\n }\n\n async cancelWorkflowRun(params: CancelWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Canceling workflow run: {workflowRunId}\", { workflowRunId: params.workflowRunId });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .whereIn(\"status\", [\"pending\", \"running\", \"sleeping\", \"paused\"])\n .update({\n status: \"canceled\",\n worker_id: null,\n available_at: null,\n finished_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n // workflow may already be in a terminal state\n const existing = await this.getWorkflowRun({\n workflowRunId: params.workflowRunId,\n });\n if (!existing) {\n throw new Error(`Workflow run ${params.workflowRunId} does not exist`);\n }\n\n // if already canceled, just return it\n if (existing.status === \"canceled\") {\n return existing;\n }\n\n // throw error for completed/failed workflows\n // 'succeeded' status is deprecated\n if ([\"succeeded\", \"completed\", \"failed\"].includes(existing.status)) {\n logger.error(\"Cannot cancel workflow run: {params} with status {status}\", {\n params,\n status: existing.status,\n });\n throw new Error(\n `Cannot cancel workflow run ${params.workflowRunId} with status ${existing.status}`,\n );\n }\n\n logger.error(\"Failed to cancel workflow run: {params}\", { params });\n throw new Error(\"Failed to cancel workflow run\");\n }\n\n return updated;\n }\n\n async pauseWorkflowRun(params: PauseWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Pausing workflow run: {workflowRunId}\", { workflowRunId: params.workflowRunId });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .whereIn(\"status\", [\"pending\", \"running\", \"sleeping\"])\n .update({\n status: \"paused\",\n worker_id: null,\n available_at: null,\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n const existing = await this.getWorkflowRun({\n workflowRunId: params.workflowRunId,\n });\n if (!existing) {\n throw new Error(`Workflow run ${params.workflowRunId} does not exist`);\n }\n\n // 이미 paused이면 멱등하게 반환합니다.\n if (existing.status === \"paused\") {\n return existing;\n }\n\n // 터미널 상태에서는 pause할 수 없습니다.\n // 'succeeded' status is deprecated\n if ([\"succeeded\", \"completed\", \"failed\", \"canceled\"].includes(existing.status)) {\n logger.error(\"Cannot pause workflow run: {params} with status {status}\", {\n params,\n status: existing.status,\n });\n throw new Error(\n `Cannot pause workflow run ${params.workflowRunId} with status ${existing.status}`,\n );\n }\n\n logger.error(\"Failed to pause workflow run: {params}\", { params });\n throw new Error(\"Failed to pause workflow run\");\n }\n\n return updated;\n }\n\n async resumeWorkflowRun(params: ResumeWorkflowRunParams): Promise<WorkflowRun> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Resuming workflow run: {workflowRunId}\", { workflowRunId: params.workflowRunId });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"workflow_runs\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.workflowRunId)\n .where(\"status\", \"paused\")\n .update({\n status: \"pending\",\n available_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!updated) {\n const existing = await this.getWorkflowRun({\n workflowRunId: params.workflowRunId,\n });\n if (!existing) {\n throw new Error(`Workflow run ${params.workflowRunId} does not exist`);\n }\n\n // 이미 pending/running이면 멱등하게 반환합니다.\n if (existing.status === \"pending\" || existing.status === \"running\") {\n return existing;\n }\n\n // 터미널 상태에서는 resume할 수 없습니다.\n // 'succeeded' status is deprecated\n if ([\"succeeded\", \"completed\", \"failed\", \"canceled\"].includes(existing.status)) {\n logger.error(\"Cannot resume workflow run: {params} with status {status}\", {\n params,\n status: existing.status,\n });\n throw new Error(\n `Cannot resume workflow run ${params.workflowRunId} with status ${existing.status}`,\n );\n }\n\n logger.error(\"Failed to resume workflow run: {params}\", { params });\n throw new Error(\"Failed to resume workflow run\");\n }\n\n return updated;\n }\n\n async createStepAttempt(params: CreateStepAttemptParams): Promise<StepAttempt> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Creating step attempt: {workflowRunId}, {stepName}, {kind}\", {\n workflowRunId: params.workflowRunId,\n stepName: params.stepName,\n kind: params.kind,\n });\n\n const [stepAttempt] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts\")\n .insert({\n namespace_id: this.namespaceId,\n id: crypto.randomUUID(),\n workflow_run_id: params.workflowRunId,\n step_name: params.stepName,\n kind: params.kind,\n status: \"running\",\n config: JSON.stringify(params.config),\n context: JSON.stringify(params.context),\n started_at: this.knex.fn.now(),\n created_at: this.knex.raw(\"date_trunc('milliseconds', NOW())\"),\n updated_at: this.knex.fn.now(),\n })\n .returning(\"*\");\n\n if (!stepAttempt) {\n logger.error(\"Failed to create step attempt: {params}\", { params });\n throw new Error(\"Failed to create step attempt\");\n }\n\n return stepAttempt;\n }\n\n async getStepAttempt(params: GetStepAttemptParams): Promise<StepAttempt | null> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Getting step attempt: {stepAttemptId}\", { stepAttemptId: params.stepAttemptId });\n\n const stepAttempt = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.stepAttemptId)\n .first();\n\n return stepAttempt ?? null;\n }\n\n async listStepAttempts(params: ListStepAttemptsParams): Promise<PaginatedResponse<StepAttempt>> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Listing step attempts: {workflowRunId}, {after}, {before}\", {\n workflowRunId: params.workflowRunId,\n after: params.after,\n before: params.before,\n });\n\n const limit = params.limit ?? DEFAULT_PAGINATION_PAGE_SIZE;\n const { after, before } = params;\n const order = params.order ?? \"asc\";\n const reverseOrder = order === \"asc\" ? \"desc\" : \"asc\";\n\n let cursor: Cursor | null = null;\n if (after) {\n cursor = decodeCursor(after);\n } else if (before) {\n cursor = decodeCursor(before);\n }\n\n const qb = this.buildListStepAttemptsWhere(params, cursor, order);\n const rows = await qb\n .orderBy(\"created_at\", before ? reverseOrder : order)\n .orderBy(\"id\", before ? reverseOrder : order)\n .limit(limit + 1);\n\n return this.processPaginationResults(\n rows,\n limit,\n typeof after === \"string\",\n typeof before === \"string\",\n );\n }\n\n private buildListStepAttemptsWhere(\n params: ListStepAttemptsParams,\n cursor: Cursor | null,\n order: \"asc\" | \"desc\",\n ) {\n const { after } = params;\n const qb = this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"workflow_run_id\", params.workflowRunId);\n\n if (cursor) {\n // asc: after → \">\", before → \"<\"\n // desc: after → \"<\", before → \">\"\n const operator = (order === \"asc\") === !!after ? \">\" : \"<\";\n return qb.whereRaw(`(\"created_at\", \"id\") ${operator} (?, ?)`, [\n cursor.createdAt.toISOString(),\n cursor.id,\n ]);\n }\n\n return qb;\n }\n\n private processPaginationResults<T extends Cursor>(\n rows: T[],\n limit: number,\n hasAfter: boolean,\n hasBefore: boolean,\n ): PaginatedResponse<T> {\n const data = rows;\n let hasNext = false;\n let hasPrev = false;\n\n if (hasBefore) {\n data.reverse();\n if (data.length > limit) {\n hasPrev = true;\n data.shift();\n }\n hasNext = true;\n } else {\n if (data.length > limit) {\n hasNext = true;\n data.pop();\n }\n if (hasAfter) {\n hasPrev = true;\n }\n }\n\n const lastItem = data.at(-1);\n const nextCursor = hasNext && lastItem ? encodeCursor(lastItem) : null;\n const firstItem = data[0];\n const prevCursor = hasPrev && firstItem ? encodeCursor(firstItem) : null;\n\n return {\n data,\n pagination: {\n next: nextCursor,\n prev: prevCursor,\n },\n };\n }\n\n // WHERE 조건에 wr.status='running', sa.status='running'이 포함되어 있어,\n // 외부에서 워크플로우 상태가 변경된 경우(pause/cancel) null을 반환합니다.\n // 예상하지 못한 이유로 실패한 경우에는 에러를 로깅합니다.\n async completeStepAttempt(params: CompleteStepAttemptParams): Promise<StepAttempt | null> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Marking step attempt as completed: {workflowRunId}, {stepAttemptId}, {workerId}\", {\n workflowRunId: params.workflowRunId,\n stepAttemptId: params.stepAttemptId,\n workerId: params.workerId,\n });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts as sa\")\n .update({\n status: \"completed\",\n output: JSON.stringify(params.output),\n error: null,\n finished_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .updateFrom(`${DEFAULT_SCHEMA}.workflow_runs as wr`)\n .where(\"sa.namespace_id\", this.namespaceId)\n .where(\"sa.workflow_run_id\", params.workflowRunId)\n .where(\"sa.id\", params.stepAttemptId)\n .where(\"sa.status\", \"running\")\n .where(\"wr.namespace_id\", this.knex.ref(\"sa.namespace_id\"))\n .where(\"wr.id\", this.knex.ref(\"sa.workflow_run_id\"))\n .where(\"wr.status\", \"running\")\n .where(\"wr.worker_id\", params.workerId)\n .returning(\"sa.*\");\n\n if (!updated) {\n return this.handleStepAttemptUpdateMiss(\"completed\", params);\n }\n\n return updated;\n }\n\n async failStepAttempt(params: FailStepAttemptParams): Promise<StepAttempt | null> {\n if (!this.initialized) {\n throw new Error(\"Backend not initialized\");\n }\n\n logger.info(\"Marking step attempt as failed: {workflowRunId}, {stepAttemptId}, {workerId}\", {\n workflowRunId: params.workflowRunId,\n stepAttemptId: params.stepAttemptId,\n workerId: params.workerId,\n });\n logger.info(\"Error: {error.message}\", { error: params.error.message });\n\n const [updated] = await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts as sa\")\n .update({\n status: \"failed\",\n output: null,\n error: JSON.stringify(params.error),\n finished_at: this.knex.fn.now(),\n updated_at: this.knex.fn.now(),\n })\n .updateFrom(`${DEFAULT_SCHEMA}.workflow_runs as wr`)\n .where(\"sa.namespace_id\", this.namespaceId)\n .where(\"sa.workflow_run_id\", params.workflowRunId)\n .where(\"sa.id\", params.stepAttemptId)\n .where(\"sa.status\", \"running\")\n .where(\"wr.namespace_id\", this.knex.ref(\"sa.namespace_id\"))\n .where(\"wr.id\", this.knex.ref(\"sa.workflow_run_id\"))\n .where(\"wr.status\", \"running\")\n .where(\"wr.worker_id\", params.workerId)\n .returning(\"sa.*\");\n\n if (!updated) {\n return this.handleStepAttemptUpdateMiss(\"failed\", params);\n }\n\n return updated;\n }\n\n /**\n * completeStepAttempt/failStepAttempt에서 UPDATE가 0건일 때,\n * 외부 상태 변경(pause/cancel)에 의한 것인지 판단합니다.\n * - 외부 상태 변경이면 해당 step의 상태도 워크플로우와 동일하게 맞추고 null을 반환합니다.\n * - 그 외에는 예상하지 못한 상황이므로 에러를 throw합니다.\n */\n private async handleStepAttemptUpdateMiss(\n method: string,\n params: { workflowRunId: string; stepAttemptId: string; workerId: string },\n ): Promise<null> {\n const wr = await this.getWorkflowRun({ workflowRunId: params.workflowRunId });\n\n // 워크플로우가 외부에서 paused/canceled된 경우 → step 상태도 동일하게 갱신하고 null 반환\n if (wr && (wr.status === \"paused\" || wr.status === \"canceled\")) {\n await this.knex\n .withSchema(DEFAULT_SCHEMA)\n .table(\"step_attempts\")\n .where(\"namespace_id\", this.namespaceId)\n .where(\"id\", params.stepAttemptId)\n .whereIn(\"status\", [\"running\", \"paused\"])\n .update({\n status: wr.status,\n updated_at: this.knex.fn.now(),\n });\n return null;\n }\n\n // 그 외(워크플로우가 여전히 running인데 UPDATE가 안 된 경우 등) → 예상 못한 상황\n logger.error(\"Failed to mark step attempt {method}: {params}\", {\n method,\n params,\n });\n throw new Error(`Failed to mark step attempt ${method}`);\n }\n}\n\n/**\n * Cursor used for pagination. Requires created_at and id fields. Because JS\n * Date does not natively support microsecond precision dates, created_at should\n * be stored with millisecond precision in paginated tables to avoid issues with\n * cursor comparisons.\n */\ninterface Cursor {\n createdAt: Date;\n id: string;\n}\n\nfunction encodeCursor(item: Cursor): string {\n const encoded = Buffer.from(\n JSON.stringify({ createdAt: item.createdAt.toISOString(), id: item.id }),\n ).toString(\"base64\");\n return encoded;\n}\n\nexport function decodeCursor(cursor: string): Cursor {\n const decoded = Buffer.from(cursor, \"base64\").toString(\"utf8\");\n const parsed = JSON.parse(decoded) as { createdAt: string; id: string };\n return {\n createdAt: new Date(parsed.createdAt),\n id: parsed.id,\n };\n}\n"],"mappings":"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"}
|
package/dist/database/base.js
CHANGED
|
@@ -1,31 +1,54 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
1
|
import knex from "knex";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
|
|
6
|
+
//#region src/database/base.ts
|
|
7
|
+
const DEFAULT_SCHEMA = "sonamu_tasks";
|
|
8
|
+
const MIGRATION_FILE_PATTERN = /\.(?:[cm]?[jt]s)$/;
|
|
9
|
+
const TYPE_DECLARATION_FILE_PATTERN = /\.d\.[cm]?[jt]s$/;
|
|
10
|
+
function toCanonicalMigrationName(fileName) {
|
|
11
|
+
return fileName.replace(/\.(?:[cm]?[jt]s)$/, ".ts");
|
|
12
|
+
}
|
|
13
|
+
async function listMigrationEntries(directory) {
|
|
14
|
+
return (await readdir(directory, { withFileTypes: true })).filter((dirent) => dirent.isFile() && MIGRATION_FILE_PATTERN.test(dirent.name) && !TYPE_DECLARATION_FILE_PATTERN.test(dirent.name)).map((dirent) => ({
|
|
15
|
+
canonicalName: toCanonicalMigrationName(dirent.name),
|
|
16
|
+
fileName: dirent.name
|
|
17
|
+
})).sort((left, right) => left.canonicalName.localeCompare(right.canonicalName));
|
|
18
|
+
}
|
|
19
|
+
function createMigrationSource(directory) {
|
|
20
|
+
return {
|
|
21
|
+
getMigrations: async (_loadExtensions) => listMigrationEntries(directory),
|
|
22
|
+
getMigrationName: (migration) => migration.fileName,
|
|
23
|
+
getMigration: async (migration) => {
|
|
24
|
+
return import(pathToFileURL(path.join(directory, migration.fileName)).href);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
* migrate applies pending migrations to the database. Does nothing if the
|
|
30
|
+
* database is already up to date.
|
|
31
|
+
*/
|
|
32
|
+
async function migrate(config, schema) {
|
|
33
|
+
const instance = knex({
|
|
34
|
+
...config,
|
|
35
|
+
pool: {
|
|
36
|
+
min: 1,
|
|
37
|
+
max: 1
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
const migrationDirectory = path.join(import.meta.dirname, "migrations");
|
|
42
|
+
await instance.schema.createSchemaIfNotExists(schema);
|
|
43
|
+
await instance.migrate.latest({
|
|
44
|
+
migrationSource: createMigrationSource(migrationDirectory),
|
|
45
|
+
schemaName: schema
|
|
46
|
+
});
|
|
47
|
+
} finally {
|
|
48
|
+
await instance.destroy();
|
|
49
|
+
}
|
|
29
50
|
}
|
|
30
51
|
|
|
52
|
+
//#endregion
|
|
53
|
+
export { DEFAULT_SCHEMA, migrate };
|
|
31
54
|
//# sourceMappingURL=base.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/database/base.ts"],"sourcesContent":["import path from \"node:path\";\nimport knex
|
|
1
|
+
{"version":3,"file":"base.js","names":[],"sources":["../../src/database/base.ts"],"sourcesContent":["import { readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport knex from \"knex\";\nimport { type Knex } from \"knex\";\n\nexport const DEFAULT_SCHEMA = \"sonamu_tasks\";\nconst MIGRATION_FILE_PATTERN = /\\.(?:[cm]?[jt]s)$/;\nconst TYPE_DECLARATION_FILE_PATTERN = /\\.d\\.[cm]?[jt]s$/;\n\ntype MigrationModule = {\n up: (knex: Knex) => Promise<void>;\n down: (knex: Knex) => Promise<void>;\n};\n\ntype MigrationEntry = {\n canonicalName: string;\n fileName: string;\n};\n\nfunction toCanonicalMigrationName(fileName: string): string {\n return fileName.replace(/\\.(?:[cm]?[jt]s)$/, \".ts\");\n}\n\nasync function listMigrationEntries(directory: string): Promise<MigrationEntry[]> {\n const dirents = await readdir(directory, { withFileTypes: true });\n\n return dirents\n .filter(\n (dirent) =>\n dirent.isFile() &&\n MIGRATION_FILE_PATTERN.test(dirent.name) &&\n !TYPE_DECLARATION_FILE_PATTERN.test(dirent.name),\n )\n .map((dirent) => ({\n canonicalName: toCanonicalMigrationName(dirent.name),\n fileName: dirent.name,\n }))\n .sort((left, right) => left.canonicalName.localeCompare(right.canonicalName));\n}\n\nexport function createMigrationSource(directory: string): Knex.MigrationSource<MigrationEntry> {\n return {\n getMigrations: async (_loadExtensions) => listMigrationEntries(directory),\n getMigrationName: (migration) => migration.fileName,\n getMigration: async (migration): Promise<MigrationModule> => {\n const migrationUrl = pathToFileURL(path.join(directory, migration.fileName)).href;\n return import(migrationUrl) as Promise<MigrationModule>;\n },\n };\n}\n\n/**\n * migrate applies pending migrations to the database. Does nothing if the\n * database is already up to date.\n */\nexport async function migrate(config: Knex.Config, schema: string) {\n const instance = knex({ ...config, pool: { min: 1, max: 1 } });\n try {\n const migrationDirectory = path.join(import.meta.dirname, \"migrations\");\n await instance.schema.createSchemaIfNotExists(schema);\n await instance.migrate.latest({\n migrationSource: createMigrationSource(migrationDirectory),\n schemaName: schema,\n });\n } finally {\n await instance.destroy();\n }\n}\n\n/**\n * dropSchema drops the specified schema from the database.\n */\nexport async function dropSchema(knex: Knex, schema: string) {\n await knex.schema.dropSchemaIfExists(schema, true);\n}\n"],"mappings":";;;;;;AAOA,MAAa,iBAAiB;AAC9B,MAAM,yBAAyB;AAC/B,MAAM,gCAAgC;AAYtC,SAAS,yBAAyB,UAA0B;AAC1D,QAAO,SAAS,QAAQ,qBAAqB,MAAM;;AAGrD,eAAe,qBAAqB,WAA8C;AAGhF,SAFgB,MAAM,QAAQ,WAAW,EAAE,eAAe,MAAM,CAAC,EAG9D,QACE,WACC,OAAO,QAAQ,IACf,uBAAuB,KAAK,OAAO,KAAK,IACxC,CAAC,8BAA8B,KAAK,OAAO,KAAK,CACnD,CACA,KAAK,YAAY;EAChB,eAAe,yBAAyB,OAAO,KAAK;EACpD,UAAU,OAAO;EAClB,EAAE,CACF,MAAM,MAAM,UAAU,KAAK,cAAc,cAAc,MAAM,cAAc,CAAC;;AAGjF,SAAgB,sBAAsB,WAAyD;AAC7F,QAAO;EACL,eAAe,OAAO,oBAAoB,qBAAqB,UAAU;EACzE,mBAAmB,cAAc,UAAU;EAC3C,cAAc,OAAO,cAAwC;AAE3D,UAAO,OADc,cAAc,KAAK,KAAK,WAAW,UAAU,SAAS,CAAC,CAAC;;EAGhF;;;;;;AAOH,eAAsB,QAAQ,QAAqB,QAAgB;CACjE,MAAM,WAAW,KAAK;EAAE,GAAG;EAAQ,MAAM;GAAE,KAAK;GAAG,KAAK;GAAG;EAAE,CAAC;AAC9D,KAAI;EACF,MAAM,qBAAqB,KAAK,KAAK,OAAO,KAAK,SAAS,aAAa;AACvE,QAAM,SAAS,OAAO,wBAAwB,OAAO;AACrD,QAAM,SAAS,QAAQ,OAAO;GAC5B,iBAAiB,sBAAsB,mBAAmB;GAC1D,YAAY;GACb,CAAC;WACM;AACR,QAAM,SAAS,SAAS"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
//#region src/database/migrations/20251212000000_0_init.d.ts
|
|
4
|
+
declare function up(knex: Knex): Promise<void>;
|
|
5
|
+
declare function down(knex: Knex): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=20251212000000_0_init.d.ts.map
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
export { down, up };
|
|
10
|
+
//# sourceMappingURL=20251212000000_0_init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20251212000000_0_init.d.ts","names":[],"sources":["../../../src/database/migrations/20251212000000_0_init.ts"],"sourcesContent":[],"mappings":";;;iBAIsB,EAAA,OAAS,OAAO;iBAIhB,IAAA,OAAW,OAAO;AAJxC"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { DEFAULT_SCHEMA } from "../base.js";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
//#region src/database/migrations/20251212000000_0_init.ts
|
|
4
|
+
async function up(knex) {
|
|
5
|
+
await knex.schema.createSchemaIfNotExists(DEFAULT_SCHEMA);
|
|
4
6
|
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
async function down(knex) {
|
|
8
|
+
await knex.schema.dropSchemaIfExists(DEFAULT_SCHEMA, true);
|
|
7
9
|
}
|
|
8
10
|
|
|
11
|
+
//#endregion
|
|
12
|
+
export { down, up };
|
|
9
13
|
//# sourceMappingURL=20251212000000_0_init.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/database/migrations/20251212000000_0_init.ts"],"sourcesContent":["import type
|
|
1
|
+
{"version":3,"file":"20251212000000_0_init.js","names":[],"sources":["../../../src/database/migrations/20251212000000_0_init.ts"],"sourcesContent":["import { type Knex } from \"knex\";\n\nimport { DEFAULT_SCHEMA } from \"../base\";\n\nexport async function up(knex: Knex): Promise<void> {\n await knex.schema.createSchemaIfNotExists(DEFAULT_SCHEMA);\n}\n\nexport async function down(knex: Knex): Promise<void> {\n await knex.schema.dropSchemaIfExists(DEFAULT_SCHEMA, true);\n}\n"],"mappings":";;;AAIA,eAAsB,GAAG,MAA2B;AAClD,OAAM,KAAK,OAAO,wBAAwB,eAAe;;AAG3D,eAAsB,KAAK,MAA2B;AACpD,OAAM,KAAK,OAAO,mBAAmB,gBAAgB,KAAK"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
//#region src/database/migrations/20251212000000_1_tables.d.ts
|
|
4
|
+
declare function up(knex: Knex): Promise<void>;
|
|
5
|
+
declare function down(knex: Knex): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=20251212000000_1_tables.d.ts.map
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
export { down, up };
|
|
10
|
+
//# sourceMappingURL=20251212000000_1_tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20251212000000_1_tables.d.ts","names":[],"sources":["../../../src/database/migrations/20251212000000_1_tables.ts"],"sourcesContent":[],"mappings":";;;iBAIsB,EAAA,OAAS,OAAO;iBA+ChB,IAAA,OAAW,OAAO;AA/CxC"}
|
|
@@ -1,88 +1,86 @@
|
|
|
1
1
|
import { DEFAULT_SCHEMA } from "../base.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"namespace_id",
|
|
79
|
-
"id"
|
|
80
|
-
]);
|
|
81
|
-
});
|
|
2
|
+
|
|
3
|
+
//#region src/database/migrations/20251212000000_1_tables.ts
|
|
4
|
+
async function up(knex) {
|
|
5
|
+
await knex.schema.withSchema(DEFAULT_SCHEMA).createTable("workflow_runs", (table) => {
|
|
6
|
+
table.text("namespace_id").notNullable();
|
|
7
|
+
table.text("id").notNullable();
|
|
8
|
+
table.text("workflow_name").notNullable();
|
|
9
|
+
table.text("version");
|
|
10
|
+
table.text("status").notNullable();
|
|
11
|
+
table.text("idempotency_key");
|
|
12
|
+
table.jsonb("config").notNullable();
|
|
13
|
+
table.jsonb("context");
|
|
14
|
+
table.jsonb("input");
|
|
15
|
+
table.jsonb("output");
|
|
16
|
+
table.jsonb("error");
|
|
17
|
+
table.integer("attempts").notNullable();
|
|
18
|
+
table.text("parent_step_attempt_namespace_id");
|
|
19
|
+
table.text("parent_step_attempt_id");
|
|
20
|
+
table.text("worker_id");
|
|
21
|
+
table.timestamp("available_at", {
|
|
22
|
+
useTz: true,
|
|
23
|
+
precision: 3
|
|
24
|
+
});
|
|
25
|
+
table.timestamp("deadline_at", {
|
|
26
|
+
useTz: true,
|
|
27
|
+
precision: 3
|
|
28
|
+
});
|
|
29
|
+
table.timestamp("started_at", {
|
|
30
|
+
useTz: true,
|
|
31
|
+
precision: 3
|
|
32
|
+
});
|
|
33
|
+
table.timestamp("finished_at", {
|
|
34
|
+
useTz: true,
|
|
35
|
+
precision: 3
|
|
36
|
+
});
|
|
37
|
+
table.timestamp("created_at", {
|
|
38
|
+
useTz: true,
|
|
39
|
+
precision: 3
|
|
40
|
+
}).notNullable();
|
|
41
|
+
table.timestamp("updated_at", {
|
|
42
|
+
useTz: true,
|
|
43
|
+
precision: 3
|
|
44
|
+
}).notNullable();
|
|
45
|
+
table.primary(["namespace_id", "id"]);
|
|
46
|
+
});
|
|
47
|
+
await knex.schema.withSchema(DEFAULT_SCHEMA).createTable("step_attempts", (table) => {
|
|
48
|
+
table.text("namespace_id").notNullable();
|
|
49
|
+
table.text("id").notNullable();
|
|
50
|
+
table.text("workflow_run_id").notNullable();
|
|
51
|
+
table.text("step_name").notNullable();
|
|
52
|
+
table.text("kind").notNullable();
|
|
53
|
+
table.text("status").notNullable();
|
|
54
|
+
table.jsonb("config").notNullable();
|
|
55
|
+
table.jsonb("context");
|
|
56
|
+
table.jsonb("output");
|
|
57
|
+
table.jsonb("error");
|
|
58
|
+
table.text("child_workflow_run_namespace_id");
|
|
59
|
+
table.text("child_workflow_run_id");
|
|
60
|
+
table.timestamp("started_at", {
|
|
61
|
+
useTz: true,
|
|
62
|
+
precision: 3
|
|
63
|
+
});
|
|
64
|
+
table.timestamp("finished_at", {
|
|
65
|
+
useTz: true,
|
|
66
|
+
precision: 3
|
|
67
|
+
});
|
|
68
|
+
table.timestamp("created_at", {
|
|
69
|
+
useTz: true,
|
|
70
|
+
precision: 3
|
|
71
|
+
}).notNullable();
|
|
72
|
+
table.timestamp("updated_at", {
|
|
73
|
+
useTz: true,
|
|
74
|
+
precision: 3
|
|
75
|
+
}).notNullable();
|
|
76
|
+
table.primary(["namespace_id", "id"]);
|
|
77
|
+
});
|
|
82
78
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
async function down(knex) {
|
|
80
|
+
await knex.schema.withSchema(DEFAULT_SCHEMA).dropTable("workflow_runs");
|
|
81
|
+
await knex.schema.withSchema(DEFAULT_SCHEMA).dropTable("step_attempts");
|
|
86
82
|
}
|
|
87
83
|
|
|
84
|
+
//#endregion
|
|
85
|
+
export { down, up };
|
|
88
86
|
//# sourceMappingURL=20251212000000_1_tables.js.map
|