@lostgradient/weft 0.12.0 → 0.13.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/README.md +1 -1
- package/dist/cli/api.d.ts +2 -0
- package/dist/cli/api.js +3 -4
- package/dist/cli/generated/operation-catalog.snapshot.json +508 -12
- package/dist/cli/generated/operation-client.generated.d.ts +118 -10
- package/dist/cli/generated/operation-client.generated.js +74 -1
- package/dist/cli/operation-catalog-snapshot.d.ts +11 -2
- package/dist/cli/operation-catalog-snapshot.js +14 -5
- package/dist/cli/operation-client-runtime.d.ts +29 -0
- package/dist/client/client-storage.d.ts +24 -0
- package/dist/client/client-storage.js +14 -0
- package/dist/client/handle-delegation.d.ts +3 -3
- package/dist/client/handle-delegation.js +2 -2
- package/dist/client/http-client-requests.d.ts +5 -3
- package/dist/client/http-client-requests.js +20 -2
- package/dist/client/http-client-storage.d.ts +3 -0
- package/dist/client/http-client-storage.js +110 -0
- package/dist/client/http-client.d.ts +9 -6
- package/dist/client/http-client.js +13 -18
- package/dist/client/http-operations.d.ts +3 -1
- package/dist/client/http-operations.js +77 -1
- package/dist/client/http-request.d.ts +15 -8
- package/dist/client/http-request.js +19 -7
- package/dist/client/in-process-operations.d.ts +2 -2
- package/dist/client/in-process-operations.js +2 -2
- package/dist/client/index.d.ts +5 -1
- package/dist/client/index.js +13 -2
- package/dist/client/interface.d.ts +26 -26
- package/dist/client/local.d.ts +9 -6
- package/dist/client/local.js +9 -4
- package/dist/client/search-params.js +10 -6
- package/dist/client/start-body.d.ts +3 -1
- package/dist/client/start-body.js +9 -0
- package/dist/core/bulk-workflow-filter.d.ts +2 -1
- package/dist/core/bulk-workflow-filter.js +5 -1
- package/dist/core/engine/async-activity-records.d.ts +12 -1
- package/dist/core/engine/async-activity-records.js +81 -2
- package/dist/core/engine/bulk-operations-purge.js +16 -1
- package/dist/core/engine/bulk-operations-shared.js +2 -0
- package/dist/core/engine/callback-creators-schedule.d.ts +2 -1
- package/dist/core/engine/callback-creators-schedule.js +3 -3
- package/dist/core/engine/checkpoint-reads.js +11 -1
- package/dist/core/engine/child-workflow.js +15 -6
- package/dist/core/engine/construction.js +3 -0
- package/dist/core/engine/disposal.js +2 -0
- package/dist/core/engine/engine-internal-types.d.ts +4 -1
- package/dist/core/engine/fenced-write.d.ts +5 -3
- package/dist/core/engine/finalizer-status.d.ts +10 -0
- package/dist/core/engine/finalizer-status.js +82 -0
- package/dist/core/engine/index.d.ts +26 -2
- package/dist/core/engine/index.js +71 -8
- package/dist/core/engine/internals.d.ts +3 -0
- package/dist/core/engine/lease-health.d.ts +64 -0
- package/dist/core/engine/lease-health.js +0 -0
- package/dist/core/engine/lease-manager.d.ts +4 -2
- package/dist/core/engine/lease-manager.js +32 -4
- package/dist/core/engine/lifecycle/recovered-services.js +0 -2
- package/dist/core/engine/lifecycle/shared.d.ts +11 -8
- package/dist/core/engine/lifecycle/start-batch.js +12 -0
- package/dist/core/engine/lifecycle/start.d.ts +1 -1
- package/dist/core/engine/lifecycle/start.js +34 -5
- package/dist/core/engine/operations-coordination.d.ts +1 -12
- package/dist/core/engine/operations-coordination.js +57 -10
- package/dist/core/engine/operations-speculate.d.ts +1 -1
- package/dist/core/engine/operations-speculate.js +19 -5
- package/dist/core/engine/registration.js +14 -0
- package/dist/core/engine/schedule-handle.d.ts +4 -4
- package/dist/core/engine/schedule-handle.js +2 -2
- package/dist/core/engine/schedule-overlap.d.ts +11 -0
- package/dist/core/engine/schedule-overlap.js +50 -0
- package/dist/core/engine/schedule-run.d.ts +11 -3
- package/dist/core/engine/schedule-run.js +27 -4
- package/dist/core/engine/schedule-timer.js +10 -1
- package/dist/core/engine/schedules.d.ts +5 -4
- package/dist/core/engine/schedules.js +62 -56
- package/dist/core/engine/state-utilities.js +1 -1
- package/dist/core/engine/storage-io.d.ts +12 -0
- package/dist/core/engine/storage-io.js +49 -10
- package/dist/core/engine/termination/finalizer-claim.d.ts +8 -6
- package/dist/core/engine/termination/finalizer-claim.js +2 -1
- package/dist/core/engine/termination/finalizer.js +10 -14
- package/dist/core/engine/timeline-coordinator-constants.d.ts +3 -0
- package/dist/core/engine/timeline-coordinator-constants.js +1 -0
- package/dist/core/engine/timeline-coordinator-detail.d.ts +13 -0
- package/dist/core/engine/timeline-coordinator-detail.js +76 -0
- package/dist/core/engine/validation/schedule-options.d.ts +8 -1
- package/dist/core/engine/validation/schedule-options.js +18 -0
- package/dist/core/engine/validation/schedule.d.ts +1 -1
- package/dist/core/engine/validation/schedule.js +27 -3
- package/dist/core/engine/validation.js +66 -2
- package/dist/core/engine/workflow-state-stream.d.ts +5 -1
- package/dist/core/engine/workflow-state-stream.js +37 -14
- package/dist/core/events/schedule-events.d.ts +3 -4
- package/dist/core/events/workflow-events.d.ts +2 -1
- package/dist/core/list-filter-validation.d.ts +3 -0
- package/dist/core/list-filter-validation.js +11 -0
- package/dist/core/registry-snapshot.d.ts +32 -0
- package/dist/core/registry-snapshot.js +28 -0
- package/dist/core/review/index.d.ts +4 -4
- package/dist/core/types/activity.d.ts +52 -5
- package/dist/core/types/bulk.d.ts +1 -0
- package/dist/core/types/list-options.d.ts +6 -0
- package/dist/core/types/options.d.ts +6 -5
- package/dist/core/types/reviews.d.ts +2 -2
- package/dist/core/types/schedules.d.ts +45 -2
- package/dist/core/types/services-resolution.d.ts +5 -5
- package/dist/core/types/state.d.ts +64 -0
- package/dist/core/types/workflow-log.d.ts +3 -2
- package/dist/core/types/workflow-observability.d.ts +50 -0
- package/dist/core/types/workflow-observability.js +0 -0
- package/dist/core/types/workflow-registry.d.ts +7 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.js +1 -0
- package/dist/http.js +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/indexeddb.js +1 -1
- package/dist/server/access-policy-metadata.d.ts +92 -0
- package/dist/server/access-policy-metadata.js +78 -0
- package/dist/server/fault-to-http.d.ts +3 -7
- package/dist/server/fault-to-http.js +2 -34
- package/dist/server/handler/index.js +1 -1
- package/dist/server/handler/route-dispatch.d.ts +10 -3
- package/dist/server/handler/route-dispatch.js +19 -4
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/interactive-operations.js +2 -0
- package/dist/server/openapi-error-responses.js +55 -4
- package/dist/server/openapi.d.ts +3 -1
- package/dist/server/openapi.js +4 -0
- package/dist/server/openrpc-document-schema.d.ts +64 -0
- package/dist/server/openrpc-document-schema.js +6 -26
- package/dist/server/openrpc.d.ts +4 -0
- package/dist/server/openrpc.js +9 -33
- package/dist/server/operation-fault.d.ts +24 -7
- package/dist/server/operation-fault.js +65 -13
- package/dist/server/operations/aggregate-workflows.d.ts +6 -0
- package/dist/server/operations/aggregate-workflows.js +3 -2
- package/dist/server/operations/async-activity.d.ts +14 -0
- package/dist/server/operations/async-activity.js +88 -4
- package/dist/server/operations/bulk-filter-helpers.d.ts +3 -0
- package/dist/server/operations/bulk-filter-helpers.js +27 -3
- package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +6 -0
- package/dist/server/operations/bulk-signal-workflows.d.ts +6 -0
- package/dist/server/operations/get-stream-chunks.js +2 -7
- package/dist/server/operations/get-system-lease.d.ts +19 -0
- package/dist/server/operations/get-system-lease.js +48 -0
- package/dist/server/operations/get-workflow-observability.d.ts +24 -0
- package/dist/server/operations/get-workflow-observability.js +80 -0
- package/dist/server/operations/get-workflow-result.js +2 -2
- package/dist/server/operations/get-workflow.d.ts +2 -2
- package/dist/server/operations/list-filter-query-extractor.js +15 -0
- package/dist/server/operations/list-workflows.d.ts +6 -0
- package/dist/server/operations/list-workflows.js +12 -3
- package/dist/server/operations/operation-helpers.d.ts +9 -18
- package/dist/server/operations/operation-helpers.js +5 -23
- package/dist/server/operations/purge-workflows.d.ts +3 -0
- package/dist/server/operations/recover-all.js +2 -1
- package/dist/server/operations/single-workflow-tag-mutation.js +2 -2
- package/dist/server/operations/sse-stream.js +2 -7
- package/dist/server/operations/storage-capabilities.d.ts +34 -0
- package/dist/server/operations/storage-capabilities.js +38 -0
- package/dist/server/operations/storage.js +8 -17
- package/dist/server/operations/stream-workflow-sse.js +3 -9
- package/dist/server/operations/update-schedule.d.ts +8 -0
- package/dist/server/operations/update-schedule.js +70 -7
- package/dist/server/operations/workflow-events-sse.js +2 -2
- package/dist/server/rest-binding.d.ts +7 -6
- package/dist/server/rest-bindings.d.ts +2 -13
- package/dist/server/rest-bindings.js +19 -10
- package/dist/server/task-queue.d.ts +7 -5
- package/dist/storage/capabilities.d.ts +1 -1
- package/dist/storage/cloudflare-value-codec.d.ts +5 -3
- package/dist/storage/cloudflare-value-codec.js +1 -1
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/index.d.ts +7 -1
- package/dist/storage/interface.d.ts +16 -4
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +4 -0
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +4 -4
- package/dist/storage/postgres.js +4 -4
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/package.json +1 -1
package/dist/client/local.d.ts
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module client/local
|
|
9
9
|
*/
|
|
10
|
-
import { type
|
|
10
|
+
import { type ClientOperationName, type ClientOperationTypes, type ClientOperations } from '../cli/generated/operation-client.generated.ts';
|
|
11
11
|
import type { Engine } from '../core/engine.ts';
|
|
12
|
-
import type { AttributeFilterKey, BulkCancelResult, BulkDeleteResult, BulkRetryFailedResult, BulkSignalResult, BulkTagResult, CoordinatedUpdateResult, DefaultActivityTypes, DefaultWorkflowRegistry, ForkOptions, ListFilter, PaginatedResult, PurgeResult, QueryDefinition, RetentionOverview, ReviewListEntry, ReviewListFilter, ScheduleFilter, ScheduleOptions, ScheduleSpec, ScheduleSummary, SearchAttributeValue, SignalDefinition, SignalDeliveryOptions, StartOptions, StartOrSignalOptions, StartOrSignalSignal, SubmitReviewOptions, TypedListFilter, UpdateDefinition, WorkflowEvent, WorkflowInput, WorkflowOutput, WorkflowRegistry, WorkflowReplay, WorkflowState, WorkflowSummary, WorkflowTimelineEntry } from '../core/types.ts';
|
|
12
|
+
import type { AttributeFilterKey, BulkCancelResult, BulkDeleteResult, BulkRetryFailedResult, BulkSignalResult, BulkTagResult, CoordinatedUpdateResult, DefaultActivityTypes, DefaultWorkflowRegistry, ForkOptions, ListFilter, PaginatedResult, PurgeResult, QueryDefinition, RetentionOverview, ReviewListEntry, ReviewListFilter, ScheduleFilter, ScheduleOptions, ScheduleSpec, ScheduleSummary, ScheduleUpdateOptions, SearchAttributeValue, SignalDefinition, SignalDeliveryOptions, StartOptions, StartOrSignalOptions, StartOrSignalSignal, SubmitReviewOptions, TypedListFilter, UpdateDefinition, WorkflowEvent, WorkflowInput, WorkflowOutput, WorkflowRegistry, WorkflowReplay, WorkflowState, WorkflowSummary, WorkflowTimelineEntry } from '../core/types.ts';
|
|
13
|
+
import { type WeftClientStorage } from './client-storage.ts';
|
|
13
14
|
import type { WorkflowEventTail } from './event-tail.ts';
|
|
14
15
|
import type { ClientHandle, ClientScheduleHandle, UpdateResult, WeftClient, WeftClientActivity } from './interface.ts';
|
|
15
16
|
import type { KnownWorkflowName, UnknownNameWhenRegistryEmpty } from './workflow-name-typing.ts';
|
|
@@ -34,8 +35,10 @@ import type { KnownWorkflowName, UnknownNameWhenRegistryEmpty } from './workflow
|
|
|
34
35
|
*/
|
|
35
36
|
export declare class LocalClient<TWorkflows extends object = DefaultWorkflowRegistry, TActivities extends object = DefaultActivityTypes> implements WeftClient {
|
|
36
37
|
#private;
|
|
37
|
-
/** Typed low-level accessor for every
|
|
38
|
-
readonly operations:
|
|
38
|
+
/** Typed low-level accessor for every client-callable operation, routed in-process. */
|
|
39
|
+
readonly operations: ClientOperations;
|
|
40
|
+
/** Raw storage administration against the engine-owned backend. */
|
|
41
|
+
readonly storage: WeftClientStorage;
|
|
39
42
|
/**
|
|
40
43
|
* Out-of-band ("async") activity completion. An activity that called
|
|
41
44
|
* `ActivityContext.completeAsync()` parks its workflow until an external
|
|
@@ -54,7 +57,7 @@ export declare class LocalClient<TWorkflows extends object = DefaultWorkflowRegi
|
|
|
54
57
|
*/
|
|
55
58
|
readonly activity: WeftClientActivity;
|
|
56
59
|
constructor(engine: Engine<TWorkflows, TActivities> | Engine);
|
|
57
|
-
call<Name extends
|
|
60
|
+
call<Name extends ClientOperationName>(name: Name, input: ClientOperationTypes[Name]['input']): Promise<ClientOperationTypes[Name]['output']>;
|
|
58
61
|
start<TName extends KnownWorkflowName>(type: TName, input: WorkflowInput<WorkflowRegistry, TName>, options?: StartOptions): Promise<ClientHandle<WorkflowOutput<WorkflowRegistry, TName>>>;
|
|
59
62
|
start<TName extends string>(type: UnknownNameWhenRegistryEmpty<TName>, input: unknown, options?: StartOptions): Promise<ClientHandle>;
|
|
60
63
|
startOrSignal<TName extends KnownWorkflowName>(type: TName, input: WorkflowInput<WorkflowRegistry, TName>, signal: StartOrSignalSignal, options?: StartOrSignalOptions): Promise<ClientHandle<WorkflowOutput<WorkflowRegistry, TName>>>;
|
|
@@ -72,7 +75,7 @@ export declare class LocalClient<TWorkflows extends object = DefaultWorkflowRegi
|
|
|
72
75
|
pauseSchedule(id: string): Promise<void>;
|
|
73
76
|
resumeSchedule(id: string): Promise<void>;
|
|
74
77
|
cancelSchedule(id: string): Promise<void>;
|
|
75
|
-
updateSchedule(id: string, newSpec: string | ScheduleSpec): Promise<void>;
|
|
78
|
+
updateSchedule(id: string, newSpec: string | ScheduleSpec, options?: ScheduleUpdateOptions): Promise<void>;
|
|
76
79
|
signal(id: string, name: SignalDefinition): Promise<void>;
|
|
77
80
|
signal<TInput>(id: string, name: SignalDefinition<TInput>, payload: TInput, options?: SignalDeliveryOptions): Promise<void>;
|
|
78
81
|
signal(id: string, name: string, payload?: unknown, options?: SignalDeliveryOptions): Promise<void>;
|
package/dist/client/local.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
CLIENT_OPERATION_NAMES,
|
|
3
|
+
CLIENT_REST_OPERATION_BINDINGS
|
|
3
4
|
} from "../cli/generated/operation-client.generated.js";
|
|
4
5
|
import { createCatalogWeftClient } from "../cli/operation-client-runtime.js";
|
|
5
6
|
import {
|
|
6
7
|
runtimeWorkflowEngine
|
|
7
8
|
} from "../core/runtime-workflow-engine.js";
|
|
8
9
|
import { messageName } from "../core/types.js";
|
|
10
|
+
import { createLocalClientStorage } from "./client-storage.js";
|
|
9
11
|
import { inProcessCatalogTransport } from "./in-process-operations.js";
|
|
10
12
|
import { createLocalWorkflowEventTail } from "./local-event-tail.js";
|
|
11
13
|
import { LocalHandle, LocalScheduleHandle } from "./local-handles.js";
|
|
@@ -14,15 +16,18 @@ export class LocalClient {
|
|
|
14
16
|
#engine;
|
|
15
17
|
#rawEngine;
|
|
16
18
|
operations;
|
|
19
|
+
storage;
|
|
17
20
|
activity;
|
|
18
21
|
constructor(engine) {
|
|
19
22
|
this.#engine = runtimeWorkflowEngine(engine);
|
|
20
23
|
this.#rawEngine = engine;
|
|
24
|
+
this.storage = createLocalClientStorage(this.#rawEngine.storage);
|
|
21
25
|
this.activity = {
|
|
26
|
+
listPending: (workflowId, options) => this.#engine.listPendingAsyncActivities(workflowId, options),
|
|
22
27
|
complete: (token, result) => this.#engine.completeAsyncActivity(token, result),
|
|
23
28
|
completeExceptionally: (token, error) => this.#engine.failAsyncActivity(token, error)
|
|
24
29
|
};
|
|
25
|
-
this.operations = createCatalogWeftClient(
|
|
30
|
+
this.operations = createCatalogWeftClient(CLIENT_OPERATION_NAMES, inProcessCatalogTransport(this.#rawEngine, new Set(Object.keys(CLIENT_REST_OPERATION_BINDINGS))));
|
|
26
31
|
}
|
|
27
32
|
call(name, input) {
|
|
28
33
|
return this.operations[name](input);
|
|
@@ -71,8 +76,8 @@ export class LocalClient {
|
|
|
71
76
|
async cancelSchedule(id) {
|
|
72
77
|
return this.#engine.cancelSchedule(id);
|
|
73
78
|
}
|
|
74
|
-
async updateSchedule(id, newSpec) {
|
|
75
|
-
return this.#engine.updateSchedule(id, newSpec);
|
|
79
|
+
async updateSchedule(id, newSpec, options) {
|
|
80
|
+
return this.#engine.updateSchedule(id, newSpec, options);
|
|
76
81
|
}
|
|
77
82
|
async signal(id, nameOrDefinition, payload, options) {
|
|
78
83
|
if (options === void 0)
|
|
@@ -29,16 +29,20 @@ function appendAttributeFilters(params, attributes) {
|
|
|
29
29
|
params.set(`attr.${key}.lte`, String(attribute.lte));
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
+
function appendOptionalSearchParameter(params, key, value) {
|
|
33
|
+
if (value !== void 0)
|
|
34
|
+
params.set(key, String(value));
|
|
35
|
+
}
|
|
32
36
|
export function buildWorkflowListSearchParams(filter) {
|
|
33
37
|
const params = new URLSearchParams;
|
|
34
38
|
appendStatusFilters(params, filter?.status);
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
appendOptionalSearchParameter(params, "type", filter?.type);
|
|
40
|
+
appendOptionalSearchParameter(params, "schedule_id", filter?.scheduleId);
|
|
41
|
+
appendOptionalSearchParameter(params, "parent_workflow_id", filter?.parentWorkflowId);
|
|
42
|
+
appendOptionalSearchParameter(params, "parent_workflow_execution_token", filter?.parentWorkflowExecutionToken);
|
|
37
43
|
appendTagFilters(params, filter?.tags);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (filter?.offset !== void 0)
|
|
41
|
-
params.set("offset", String(filter.offset));
|
|
44
|
+
appendOptionalSearchParameter(params, "limit", filter?.limit);
|
|
45
|
+
appendOptionalSearchParameter(params, "offset", filter?.offset);
|
|
42
46
|
appendAttributeFilters(params, filter?.attributes);
|
|
43
47
|
return params;
|
|
44
48
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ScheduleSpec, StartOrSignalSignal } from '../core/types.ts';
|
|
1
|
+
import type { ScheduleOptions, ScheduleSpec, StartOrSignalSignal } from '../core/types.ts';
|
|
2
2
|
import type { ClientStartOptions, ClientStartOrSignalOptions } from './interface.ts';
|
|
3
3
|
export declare function setIfDefined(body: Record<string, unknown>, key: string, value: unknown): void;
|
|
4
4
|
/**
|
|
@@ -7,6 +7,8 @@ export declare function setIfDefined(body: Record<string, unknown>, key: string,
|
|
|
7
7
|
* `cronExpression`; an interval spec is sent as `every`.
|
|
8
8
|
*/
|
|
9
9
|
export declare function scheduleSpecToWireFields(spec: string | ScheduleSpec): Record<string, unknown>;
|
|
10
|
+
/** Build a schedule-create wire body from the explicitly supported option fields. */
|
|
11
|
+
export declare function buildScheduleBody(type: string, input: unknown, spec: string | ScheduleSpec, options?: ScheduleOptions): Record<string, unknown>;
|
|
10
12
|
export declare function buildStartBody(type: string, input: unknown, options?: ClientStartOptions): Record<string, unknown>;
|
|
11
13
|
/**
|
|
12
14
|
* Build the wire body for `weft.workflows.startorsignal`. Flattens the signal
|
|
@@ -9,6 +9,15 @@ export function scheduleSpecToWireFields(spec) {
|
|
|
9
9
|
return { every: spec.every };
|
|
10
10
|
return { cronExpression: spec.cron };
|
|
11
11
|
}
|
|
12
|
+
export function buildScheduleBody(type, input, spec, options) {
|
|
13
|
+
const body = { type, input, ...scheduleSpecToWireFields(spec) };
|
|
14
|
+
setIfDefined(body, "id", options?.id);
|
|
15
|
+
setIfDefined(body, "description", options?.description);
|
|
16
|
+
setIfDefined(body, "overlap", options?.overlap);
|
|
17
|
+
setIfDefined(body, "backfill", options?.backfill);
|
|
18
|
+
setIfDefined(body, "jitter", options?.jitter);
|
|
19
|
+
return body;
|
|
20
|
+
}
|
|
12
21
|
function applyStartOptionsToBody(body, options) {
|
|
13
22
|
setIfDefined(body, "id", options?.id);
|
|
14
23
|
setIfDefined(body, "executionTimeout", options?.executionTimeout);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ListFilter } from './types.ts';
|
|
2
|
-
export declare const BULK_WORKFLOW_FILTER_ERROR_MESSAGE = "Field \"filter\" must include at least one of status, type, tags, attributes, idPrefix (\u22653 chars), or failureCategory paired with status";
|
|
2
|
+
export declare const BULK_WORKFLOW_FILTER_ERROR_MESSAGE = "Field \"filter\" must include at least one of status, type, scheduleId, tags, attributes, idPrefix (\u22653 chars), or failureCategory paired with status";
|
|
3
3
|
/**
|
|
4
4
|
* Returns `true` when the filter narrows destructive bulk operations
|
|
5
5
|
* to a scoped subset rather than every workflow on the engine.
|
|
@@ -7,6 +7,7 @@ export declare const BULK_WORKFLOW_FILTER_ERROR_MESSAGE = "Field \"filter\" must
|
|
|
7
7
|
* Valid scopes:
|
|
8
8
|
* - `status` (non-empty after normalization).
|
|
9
9
|
* - `type` (non-empty after trim).
|
|
10
|
+
* - `scheduleId` (non-empty after trim).
|
|
10
11
|
* - `tags` (at least one tag after normalization).
|
|
11
12
|
* - `attributes` (at least one attribute predicate with a non-empty key).
|
|
12
13
|
* - `idPrefix` (length ≥ 3 — short prefixes match too much to be a safe scope).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { searchAttributeName } from "./search-attributes.js";
|
|
2
2
|
import { normalizeWorkflowTags } from "./workflow-tags.js";
|
|
3
3
|
const ID_PREFIX_MIN_LENGTH = 3;
|
|
4
|
-
export const BULK_WORKFLOW_FILTER_ERROR_MESSAGE = 'Field "filter" must include at least one of status, type, tags, attributes, idPrefix (\u22653 chars), or failureCategory paired with status';
|
|
4
|
+
export const BULK_WORKFLOW_FILTER_ERROR_MESSAGE = 'Field "filter" must include at least one of status, type, scheduleId, tags, attributes, idPrefix (\u22653 chars), or failureCategory paired with status';
|
|
5
5
|
function hasScopedStatusFilter(filter) {
|
|
6
6
|
if (filter.status === void 0)
|
|
7
7
|
return !1;
|
|
@@ -12,6 +12,9 @@ function hasScopedStatusFilter(filter) {
|
|
|
12
12
|
function hasScopedTypeFilter(filter) {
|
|
13
13
|
return filter.type !== void 0 && filter.type.trim().length > 0;
|
|
14
14
|
}
|
|
15
|
+
function hasScopedScheduleFilter(filter) {
|
|
16
|
+
return filter.scheduleId !== void 0 && filter.scheduleId.trim().length > 0;
|
|
17
|
+
}
|
|
15
18
|
function hasScopedTagsFilter(filter) {
|
|
16
19
|
return (normalizeWorkflowTags(filter.tags)?.length ?? 0) > 0;
|
|
17
20
|
}
|
|
@@ -24,6 +27,7 @@ function hasScopedIdPrefix(filter) {
|
|
|
24
27
|
const BULK_FILTER_DIMENSION_CHECKS = {
|
|
25
28
|
status: hasScopedStatusFilter,
|
|
26
29
|
type: hasScopedTypeFilter,
|
|
30
|
+
scheduleId: hasScopedScheduleFilter,
|
|
27
31
|
tags: hasScopedTagsFilter,
|
|
28
32
|
attributes: hasScopedAttributesFilter,
|
|
29
33
|
idPrefix: hasScopedIdPrefix
|
|
@@ -16,8 +16,11 @@
|
|
|
16
16
|
* key derivations, and the in-memory resolution queue that recovery drains.
|
|
17
17
|
*/
|
|
18
18
|
import { type BatchOperation } from '../../storage/interface.ts';
|
|
19
|
-
import type { OperationOutcome } from '../types.ts';
|
|
19
|
+
import type { OperationOutcome, PendingAsyncActivityListOptions, PendingAsyncActivityPage } from '../types.ts';
|
|
20
20
|
import type { EngineInternals } from './internals.ts';
|
|
21
|
+
export declare const DEFAULT_PENDING_ASYNC_ACTIVITY_LIMIT = 50;
|
|
22
|
+
export declare const MAX_PENDING_ASYNC_ACTIVITY_LIMIT = 200;
|
|
23
|
+
export declare const MAX_PENDING_ASYNC_ACTIVITY_CURSOR_LENGTH = 8192;
|
|
21
24
|
/**
|
|
22
25
|
* Storage-key prefix for durable async-activity records. Matches the base of
|
|
23
26
|
* {@link KEYS.asyncActivity}; the full key appends `<workflowId>:<token>` (and
|
|
@@ -60,6 +63,14 @@ export type PendingAsyncActivityResolution = {
|
|
|
60
63
|
readonly timelineStatus: 'completed' | 'failed';
|
|
61
64
|
readonly timelineOutput: unknown;
|
|
62
65
|
};
|
|
66
|
+
export declare function isPendingAsyncActivityCursor(cursor: string): boolean;
|
|
67
|
+
export declare function isPendingAsyncActivityCursorForWorkflow(cursor: string, workflowId: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Read a bounded page directly from the durable per-workflow async-activity
|
|
70
|
+
* namespace. Pagination advances over raw storage keys, so corrupt or resolved
|
|
71
|
+
* records cannot stall a caller or expand one request beyond `limit + 1` reads.
|
|
72
|
+
*/
|
|
73
|
+
export declare function listPendingAsyncActivities(internals: EngineInternals, workflowId: string, options?: PendingAsyncActivityListOptions): Promise<PendingAsyncActivityPage>;
|
|
63
74
|
/**
|
|
64
75
|
* Derive the durable, deterministic task token for an async activity.
|
|
65
76
|
*
|
|
@@ -2,8 +2,8 @@ import { KEYS, encodeStorageKeyComponent } from "../../storage/interface.js";
|
|
|
2
2
|
import { decode, encode } from "../codec.js";
|
|
3
3
|
import { ActivityAsyncPendingEvent } from "../events.js";
|
|
4
4
|
import { commitFencedEngineWrite } from "./fenced-write.js";
|
|
5
|
-
const ASYNC_ACTIVITY_TOKEN_PREFIX = "async-act:v1";
|
|
6
|
-
export const ASYNC_ACTIVITY_KEY_PREFIX = "async-act:v1:";
|
|
5
|
+
const ASYNC_ACTIVITY_TOKEN_PREFIX = "async-act:v1", PENDING_ASYNC_ACTIVITY_CURSOR_PREFIX = "pending-async:v1:";
|
|
6
|
+
export const DEFAULT_PENDING_ASYNC_ACTIVITY_LIMIT = 50, MAX_PENDING_ASYNC_ACTIVITY_LIMIT = 200, MAX_PENDING_ASYNC_ACTIVITY_CURSOR_LENGTH = 8192, ASYNC_ACTIVITY_KEY_PREFIX = "async-act:v1:";
|
|
7
7
|
export function asyncActivityWorkflowPrefix(workflowId) {
|
|
8
8
|
return `${ASYNC_ACTIVITY_KEY_PREFIX}${encodeStorageKeyComponent(workflowId)}:`;
|
|
9
9
|
}
|
|
@@ -13,6 +13,85 @@ function isPersistedAsyncActivity(value) {
|
|
|
13
13
|
const record = value;
|
|
14
14
|
return record.version === 1 && typeof record.token === "string" && typeof record.workflowId === "string" && typeof record.activityName === "string" && typeof record.operationId === "string" && typeof record.step === "number" && typeof record.attempt === "number" && typeof record.createdAt === "number";
|
|
15
15
|
}
|
|
16
|
+
function decodePendingAsyncActivityCursor(cursor) {
|
|
17
|
+
if (cursor.length > MAX_PENDING_ASYNC_ACTIVITY_CURSOR_LENGTH || !cursor.startsWith(PENDING_ASYNC_ACTIVITY_CURSOR_PREFIX))
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
const suffix = decodeURIComponent(cursor.slice(PENDING_ASYNC_ACTIVITY_CURSOR_PREFIX.length));
|
|
21
|
+
return suffix.length > 0 ? suffix : null;
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function isPendingAsyncActivityCursor(cursor) {
|
|
27
|
+
return decodePendingAsyncActivityCursor(cursor) !== null;
|
|
28
|
+
}
|
|
29
|
+
export function isPendingAsyncActivityCursorForWorkflow(cursor, workflowId) {
|
|
30
|
+
const key = decodePendingAsyncActivityCursor(cursor), prefix = asyncActivityWorkflowPrefix(workflowId);
|
|
31
|
+
return key !== null && key.startsWith(prefix) && key.length > prefix.length;
|
|
32
|
+
}
|
|
33
|
+
function encodePendingAsyncActivityCursor(key) {
|
|
34
|
+
return `${PENDING_ASYNC_ACTIVITY_CURSOR_PREFIX}${encodeURIComponent(key)}`;
|
|
35
|
+
}
|
|
36
|
+
function resolvePendingAsyncActivityLimit(limit) {
|
|
37
|
+
const resolved = limit ?? DEFAULT_PENDING_ASYNC_ACTIVITY_LIMIT;
|
|
38
|
+
if (!Number.isSafeInteger(resolved) || resolved < 1 || resolved > MAX_PENDING_ASYNC_ACTIVITY_LIMIT)
|
|
39
|
+
throw RangeError(`Pending async activity limit must be an integer between 1 and ${MAX_PENDING_ASYNC_ACTIVITY_LIMIT}.`);
|
|
40
|
+
return resolved;
|
|
41
|
+
}
|
|
42
|
+
function toPendingAsyncActivityInfo(value, key, workflowId) {
|
|
43
|
+
if (!isPersistedAsyncActivity(value))
|
|
44
|
+
return null;
|
|
45
|
+
if (value.workflowId !== workflowId || key !== KEYS.asyncActivity(workflowId, value.token))
|
|
46
|
+
return null;
|
|
47
|
+
if (!Number.isSafeInteger(value.step) || value.step < 0 || !Number.isSafeInteger(value.attempt) || value.attempt < 1 || !Number.isFinite(value.createdAt))
|
|
48
|
+
return null;
|
|
49
|
+
return {
|
|
50
|
+
token: value.token,
|
|
51
|
+
operationId: value.operationId,
|
|
52
|
+
activityName: value.activityName,
|
|
53
|
+
step: value.step,
|
|
54
|
+
attempt: value.attempt,
|
|
55
|
+
createdAt: value.createdAt
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function resolvePendingAsyncActivityAfterKey(cursor, workflowId) {
|
|
59
|
+
if (cursor === void 0)
|
|
60
|
+
return;
|
|
61
|
+
const key = decodePendingAsyncActivityCursor(cursor);
|
|
62
|
+
if (key === null || !isPendingAsyncActivityCursorForWorkflow(cursor, workflowId))
|
|
63
|
+
throw TypeError("Invalid pending async activity cursor.");
|
|
64
|
+
return key;
|
|
65
|
+
}
|
|
66
|
+
function decodePendingAsyncActivityInfo(bytes, key, workflowId) {
|
|
67
|
+
try {
|
|
68
|
+
return toPendingAsyncActivityInfo(decode(bytes), key, workflowId);
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function pendingAsyncActivityPage(scanned, limit, workflowId) {
|
|
74
|
+
const pageEntries = scanned.slice(0, limit), items = pageEntries.flatMap(([key, bytes]) => {
|
|
75
|
+
const item = decodePendingAsyncActivityInfo(bytes, key, workflowId);
|
|
76
|
+
return item === null ? [] : [item];
|
|
77
|
+
}), cursorKey = pageEntries.at(-1)?.[0];
|
|
78
|
+
return {
|
|
79
|
+
items,
|
|
80
|
+
...scanned.length > limit && cursorKey !== void 0 ? { nextCursor: encodePendingAsyncActivityCursor(cursorKey) } : {}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export async function listPendingAsyncActivities(internals, workflowId, options = {}) {
|
|
84
|
+
const limit = resolvePendingAsyncActivityLimit(options.limit), prefix = asyncActivityWorkflowPrefix(workflowId), afterKey = resolvePendingAsyncActivityAfterKey(options.cursor, workflowId), scanned = [];
|
|
85
|
+
for await (const entry of internals.storage.scan(prefix, {
|
|
86
|
+
limit: limit + 1,
|
|
87
|
+
...afterKey === void 0 ? {} : { gt: afterKey }
|
|
88
|
+
})) {
|
|
89
|
+
scanned.push(entry);
|
|
90
|
+
if (scanned.length >= limit + 1)
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
return pendingAsyncActivityPage(scanned, limit, workflowId);
|
|
94
|
+
}
|
|
16
95
|
function isPersistedOperationOutcome(value) {
|
|
17
96
|
if (typeof value !== "object" || value === null)
|
|
18
97
|
return !1;
|
|
@@ -12,6 +12,7 @@ import { asyncActivityWorkflowPrefix } from "./async-activity-records.js";
|
|
|
12
12
|
import { forgetCommittedCheckpointBytes } from "./checkpoint-commit-snapshots.js";
|
|
13
13
|
import { commitFencedEngineWrite } from "./fenced-write.js";
|
|
14
14
|
import { streamWorkflowStates } from "./listing.js";
|
|
15
|
+
import { decodeScheduleRunMetadata } from "./schedule-run-metadata.js";
|
|
15
16
|
import { createTerminalCleanupTimerId } from "./state-utilities.js";
|
|
16
17
|
import {
|
|
17
18
|
decodeWorkflowState,
|
|
@@ -181,12 +182,22 @@ async function collectWorkflowPurgeDeleteKeys(internals, state) {
|
|
|
181
182
|
const workflowId = state.id, deleteKeys = buildBaseWorkflowDeleteKeys(state);
|
|
182
183
|
addExecutionDeadlineDeleteKeys(deleteKeys, state);
|
|
183
184
|
addTerminalCleanupDeleteKey(deleteKeys, state);
|
|
185
|
+
await addScheduleRunHistoryDeleteKeys(internals.storage, deleteKeys, workflowId);
|
|
184
186
|
await addUpdateRequestDeleteKeys(internals.storage, deleteKeys, workflowId);
|
|
185
187
|
await addWorkflowPrefixDeleteKeys(internals.storage, deleteKeys, workflowId);
|
|
186
188
|
return deleteKeys;
|
|
187
189
|
}
|
|
190
|
+
async function addScheduleRunHistoryDeleteKeys(storage, deleteKeys, workflowId) {
|
|
191
|
+
const linkKey = KEYS.scheduleRunLink(workflowId), linkBytes = await storage.get(linkKey);
|
|
192
|
+
deleteKeys.add(linkKey);
|
|
193
|
+
if (linkBytes === null)
|
|
194
|
+
return;
|
|
195
|
+
const metadata = decodeScheduleRunMetadata(linkBytes);
|
|
196
|
+
if (metadata !== null)
|
|
197
|
+
deleteKeys.add(KEYS.scheduleRunBySchedule(metadata.id, workflowId));
|
|
198
|
+
}
|
|
188
199
|
function buildBaseWorkflowDeleteKeys(state) {
|
|
189
|
-
|
|
200
|
+
const keys = new Set([
|
|
190
201
|
KEYS.workflow(state.id),
|
|
191
202
|
KEYS.checkpoint(state.id),
|
|
192
203
|
KEYS.workflowHeaders(state.id),
|
|
@@ -196,9 +207,13 @@ function buildBaseWorkflowDeleteKeys(state) {
|
|
|
196
207
|
KEYS.workflowHasServices(state.id),
|
|
197
208
|
KEYS.finalizerState(state.id),
|
|
198
209
|
KEYS.teardownOwed(state.id),
|
|
210
|
+
KEYS.teardownSucceeded(state.id),
|
|
199
211
|
KEYS.attribute(state.id),
|
|
200
212
|
KEYS.terminalWorkflow(state.updatedAt, state.id)
|
|
201
213
|
]);
|
|
214
|
+
if (state.parentWorkflowId !== void 0)
|
|
215
|
+
keys.add(KEYS.childWorkflowByParent(state.parentWorkflowId, state.parentWorkflowExecutionToken, state.id));
|
|
216
|
+
return keys;
|
|
202
217
|
}
|
|
203
218
|
function addExecutionDeadlineDeleteKeys(deleteKeys, state) {
|
|
204
219
|
if (state.executionDeadline === void 0)
|
|
@@ -63,6 +63,8 @@ function summarizeBulkFilter(filter) {
|
|
|
63
63
|
summary.status = Array.isArray(filter.status) ? uniqueSorted(filter.status) : filter.status;
|
|
64
64
|
if (filter.type !== void 0)
|
|
65
65
|
summary.type = filter.type;
|
|
66
|
+
if (filter.scheduleId !== void 0)
|
|
67
|
+
summary.scheduleId = filter.scheduleId;
|
|
66
68
|
const normalizedTags = normalizeWorkflowTags(filter.tags);
|
|
67
69
|
if (normalizedTags !== void 0)
|
|
68
70
|
summary.tags = normalizedTags;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { ScheduleState, TimerEntry } from '../types.ts';
|
|
2
2
|
import type { Engine } from './index.ts';
|
|
3
3
|
import type { ReviewOperationCallbacks, SubmitReviewCallbacks } from './reviews.ts';
|
|
4
|
+
import type { ScheduledRunStartOptions } from './schedule-run.ts';
|
|
4
5
|
import { type RefreshedScheduleState, type ScheduleCallbacks } from './schedules.ts';
|
|
5
6
|
export declare function createScheduleCallbacks<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>): ScheduleCallbacks;
|
|
6
7
|
export declare function createReviewOperationCallbacks<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>): ReviewOperationCallbacks;
|
|
7
8
|
export declare function createSubmitReviewCallbacks<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>): SubmitReviewCallbacks;
|
|
8
9
|
export declare function refreshScheduledWorkflowStateForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState): Promise<RefreshedScheduleState>;
|
|
9
|
-
export declare function startScheduledRunForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState,
|
|
10
|
+
export declare function startScheduledRunForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState, options?: ScheduledRunStartOptions): Promise<string>;
|
|
10
11
|
export declare function applyScheduleOccurrenceForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState, occurrence?: number): Promise<ScheduleState>;
|
|
11
12
|
export declare function settleBackfillScheduleStateForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState): Promise<ScheduleState>;
|
|
12
13
|
export declare function handleScheduleTimerForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, entry: TimerEntry): Promise<void>;
|
|
@@ -27,7 +27,7 @@ export function createScheduleCallbacks(engine) {
|
|
|
27
27
|
cancelWorkflow: (workflowId) => engine.cancel(workflowId),
|
|
28
28
|
getWorkflowResult: (workflowId) => engine.getHandle(workflowId).result(),
|
|
29
29
|
refreshScheduledWorkflowState: (state) => refreshScheduledWorkflowStateForEngine(engine, state),
|
|
30
|
-
startScheduledRun: (state,
|
|
30
|
+
startScheduledRun: (state, options) => startScheduledRunForEngine(engine, state, options),
|
|
31
31
|
applyScheduleOccurrence: (state, occurrence) => applyScheduleOccurrenceForEngine(engine, state, occurrence),
|
|
32
32
|
settleBackfillScheduleState: (state) => settleBackfillScheduleStateForEngine(engine, state),
|
|
33
33
|
flushQueuedInlineWorkflowStartsDirectly: () => flushQueuedInlineWorkflowStartsDirectly(getInternals(engine), createInlineLaunchQueueCallbacks(engine)),
|
|
@@ -51,8 +51,8 @@ export function createSubmitReviewCallbacks(engine) {
|
|
|
51
51
|
export async function refreshScheduledWorkflowStateForEngine(engine, state) {
|
|
52
52
|
return refreshScheduledWorkflowState(getInternals(engine), state, createScheduleCallbacks(engine));
|
|
53
53
|
}
|
|
54
|
-
export async function startScheduledRunForEngine(engine, state,
|
|
55
|
-
return startScheduledRun(getInternals(engine), state, createScheduleCallbacks(engine),
|
|
54
|
+
export async function startScheduledRunForEngine(engine, state, options) {
|
|
55
|
+
return startScheduledRun(getInternals(engine), state, createScheduleCallbacks(engine), options);
|
|
56
56
|
}
|
|
57
57
|
export async function applyScheduleOccurrenceForEngine(engine, state, occurrence) {
|
|
58
58
|
return applyScheduleOccurrence(getInternals(engine), state, createScheduleCallbacks(engine), occurrence);
|
|
@@ -66,12 +66,22 @@ export async function getTimeline(internals, workflowId) {
|
|
|
66
66
|
inputSummary: sanitizeTimelineSummary(decoded.inputSummary) ?? decoded.inputSummary,
|
|
67
67
|
...decoded.outputSummary !== void 0 ? {
|
|
68
68
|
outputSummary: sanitizeTimelineSummary(decoded.outputSummary) ?? decoded.outputSummary
|
|
69
|
-
} : {}
|
|
69
|
+
} : {},
|
|
70
|
+
...decoded.branches === void 0 ? {} : { branches: decoded.branches.map(sanitizeTimelineOperationDetail) },
|
|
71
|
+
...decoded.children === void 0 ? {} : { children: decoded.children.map(sanitizeTimelineOperationDetail) }
|
|
70
72
|
});
|
|
71
73
|
}
|
|
72
74
|
timeline.sort((left, right) => left.step - right.step);
|
|
73
75
|
return timeline;
|
|
74
76
|
}
|
|
77
|
+
function sanitizeTimelineOperationDetail(detail) {
|
|
78
|
+
if (detail.errorSummary === void 0)
|
|
79
|
+
return detail;
|
|
80
|
+
return {
|
|
81
|
+
...detail,
|
|
82
|
+
errorSummary: sanitizeTimelineSummary(detail.errorSummary) ?? detail.errorSummary
|
|
83
|
+
};
|
|
84
|
+
}
|
|
75
85
|
export async function replayTo(internals, workflowId, step) {
|
|
76
86
|
const bytes = await internals.storage.get(KEYS.checkpointHistory(workflowId, step));
|
|
77
87
|
if (!bytes)
|
|
@@ -22,6 +22,8 @@ function applyPendingChildExecutionContext(internals, context) {
|
|
|
22
22
|
internals.pendingNestingDepth = context.pendingNestingDepth;
|
|
23
23
|
internals.pendingParentHeaders = context.pendingParentHeaders;
|
|
24
24
|
internals.pendingExecutionStateOwnerId = context.pendingExecutionStateOwnerId;
|
|
25
|
+
internals.pendingParentWorkflowId = context.pendingParentWorkflowId;
|
|
26
|
+
internals.pendingParentWorkflowExecutionToken = context.pendingParentWorkflowExecutionToken;
|
|
25
27
|
}
|
|
26
28
|
function clearPendingChildExecutionContext(internals, context) {
|
|
27
29
|
if (internals.pendingNestingDepth === context.pendingNestingDepth)
|
|
@@ -30,15 +32,20 @@ function clearPendingChildExecutionContext(internals, context) {
|
|
|
30
32
|
internals.pendingParentHeaders = void 0;
|
|
31
33
|
if (internals.pendingExecutionStateOwnerId === context.pendingExecutionStateOwnerId)
|
|
32
34
|
internals.pendingExecutionStateOwnerId = void 0;
|
|
35
|
+
if (internals.pendingParentWorkflowId === context.pendingParentWorkflowId)
|
|
36
|
+
internals.pendingParentWorkflowId = void 0;
|
|
37
|
+
if (internals.pendingParentWorkflowExecutionToken === context.pendingParentWorkflowExecutionToken)
|
|
38
|
+
internals.pendingParentWorkflowExecutionToken = void 0;
|
|
33
39
|
}
|
|
34
|
-
function existingChildMatchesRequest(existingState, operation, executionStateOwnerId) {
|
|
35
|
-
|
|
40
|
+
function existingChildMatchesRequest(existingState, operation, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken) {
|
|
41
|
+
const lineageMatches = existingState.parentWorkflowId === void 0 && existingState.parentWorkflowExecutionToken === void 0 || existingState.parentWorkflowId === parentWorkflowId && existingState.parentWorkflowExecutionToken === parentWorkflowExecutionToken;
|
|
42
|
+
return existingState.type === operation.workflowType && encodedValuesEqual(existingState.input, operation.input) && existingState.executionStateOwnerId === executionStateOwnerId && lineageMatches;
|
|
36
43
|
}
|
|
37
|
-
async function resolveCollisionChildHandle(childWorkflowId, operation, executionStateOwnerId, collisionError, callbacks) {
|
|
44
|
+
async function resolveCollisionChildHandle(childWorkflowId, operation, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken, collisionError, callbacks) {
|
|
38
45
|
const existingState = await callbacks.loadWorkflowState(childWorkflowId);
|
|
39
46
|
if (!existingState)
|
|
40
47
|
throw collisionError;
|
|
41
|
-
if (!existingChildMatchesRequest(existingState, operation, executionStateOwnerId))
|
|
48
|
+
if (!existingChildMatchesRequest(existingState, operation, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken))
|
|
42
49
|
throw Error(`Child workflow id collision for "${childWorkflowId}" does not match the requested child workflow`, { cause: collisionError });
|
|
43
50
|
return callbacks.getHandle(childWorkflowId);
|
|
44
51
|
}
|
|
@@ -52,7 +59,7 @@ async function dispatchChildWorkflowStart(internals, childWorkflowId, operation,
|
|
|
52
59
|
} catch (error) {
|
|
53
60
|
if (!(error instanceof WorkflowAlreadyExistsError))
|
|
54
61
|
throw error;
|
|
55
|
-
return resolveCollisionChildHandle(childWorkflowId, operation, context.pendingExecutionStateOwnerId ?? void 0, error, callbacks);
|
|
62
|
+
return resolveCollisionChildHandle(childWorkflowId, operation, context.pendingExecutionStateOwnerId ?? void 0, context.pendingParentWorkflowId, context.pendingParentWorkflowExecutionToken, error, callbacks);
|
|
56
63
|
} finally {
|
|
57
64
|
clearPendingChildExecutionContext(internals, context);
|
|
58
65
|
}
|
|
@@ -62,7 +69,9 @@ export async function executeChildWorkflow(internals, workflowId, operation, cur
|
|
|
62
69
|
const context = {
|
|
63
70
|
pendingNestingDepth: currentDepth + 1,
|
|
64
71
|
pendingParentHeaders: internals.workflowHeaders.get(workflowId),
|
|
65
|
-
pendingExecutionStateOwnerId: executionStateOwnerId
|
|
72
|
+
pendingExecutionStateOwnerId: executionStateOwnerId,
|
|
73
|
+
pendingParentWorkflowId: workflowId,
|
|
74
|
+
pendingParentWorkflowExecutionToken: parentState?.workflowExecutionToken
|
|
66
75
|
}, childHandle = await dispatchChildWorkflowStart(internals, childWorkflowId, operation, context, callbacks);
|
|
67
76
|
if (parentClosePolicy === "abandon")
|
|
68
77
|
return createChildWorkflowHandleReference(childHandle.id);
|
|
@@ -72,6 +72,9 @@ export function copyWorkflowDefinition(type, registration) {
|
|
|
72
72
|
...registration.description === void 0 ? {} : { description: registration.description },
|
|
73
73
|
...registration.inputSchema === void 0 ? {} : { inputSchema: registration.inputSchema },
|
|
74
74
|
...registration.outputSchema === void 0 ? {} : { outputSchema: registration.outputSchema },
|
|
75
|
+
...registration.signals === void 0 ? {} : { signals: { ...registration.signals } },
|
|
76
|
+
...registration.updates === void 0 ? {} : { updates: { ...registration.updates } },
|
|
77
|
+
...registration.queries === void 0 ? {} : { queries: { ...registration.queries } },
|
|
75
78
|
...registration.searchAttributes === void 0 ? {} : { searchAttributes: registration.searchAttributes },
|
|
76
79
|
...registration.concurrency === void 0 ? {} : { concurrency: registration.concurrency }
|
|
77
80
|
};
|
|
@@ -53,6 +53,8 @@ export function disposeEngine(internals) {
|
|
|
53
53
|
internals.sleepTimersFiredWithoutResolver.clear();
|
|
54
54
|
internals.checkpoints.clear();
|
|
55
55
|
internals.pendingExecutionStateOwnerId = void 0;
|
|
56
|
+
internals.pendingParentWorkflowId = void 0;
|
|
57
|
+
internals.pendingParentWorkflowExecutionToken = void 0;
|
|
56
58
|
internals.workflowNestingDepths.clear();
|
|
57
59
|
internals.workflowServices.clear();
|
|
58
60
|
internals.workflowHeaders.clear();
|
|
@@ -2,7 +2,7 @@ import type { Storage as WeftStorage } from '../../storage/interface.ts';
|
|
|
2
2
|
import type { ConstraintDefinition } from '../constraint.ts';
|
|
3
3
|
import type { ExecutionStrategy } from '../execution-strategy.ts';
|
|
4
4
|
import type { InlineExecutionStrategy } from '../inline-execution-strategy.ts';
|
|
5
|
-
import type { AnyActivityDefinition, ArchiveAdapter, Checkpoint, DefinitionSchema, EngineOptions, NormalizedHistoryPolicy, NormalizedPayloadSizePolicy, NormalizedRetentionPolicy, SearchAttributeSchema, WorkflowConcurrencyOptions, WorkflowFunction, WorkflowTimelineEntry } from '../types.ts';
|
|
5
|
+
import type { AnyActivityDefinition, ArchiveAdapter, Checkpoint, DefinitionSchema, EngineOptions, NormalizedHistoryPolicy, NormalizedPayloadSizePolicy, NormalizedRetentionPolicy, QueryDefinition, SearchAttributeSchema, SignalDefinition, UpdateDefinition, WorkflowConcurrencyOptions, WorkflowFunction, WorkflowTimelineEntry } from '../types.ts';
|
|
6
6
|
export interface RegistrationEntry {
|
|
7
7
|
handler: WorkflowFunction;
|
|
8
8
|
version: string;
|
|
@@ -10,6 +10,9 @@ export interface RegistrationEntry {
|
|
|
10
10
|
tags?: ReadonlyArray<string>;
|
|
11
11
|
inputSchema?: DefinitionSchema;
|
|
12
12
|
outputSchema?: DefinitionSchema;
|
|
13
|
+
signals?: Readonly<Record<string, Readonly<SignalDefinition<unknown>>>>;
|
|
14
|
+
updates?: Readonly<Record<string, Readonly<UpdateDefinition<unknown>>>>;
|
|
15
|
+
queries?: Readonly<Record<string, Readonly<QueryDefinition<unknown>>>>;
|
|
13
16
|
searchAttributes?: SearchAttributeSchema;
|
|
14
17
|
retention?: NormalizedRetentionPolicy;
|
|
15
18
|
concurrency?: WorkflowConcurrencyOptions;
|
|
@@ -27,9 +27,11 @@ import type { EngineInternals } from './internals.ts';
|
|
|
27
27
|
* work before `recoverAll()` would otherwise durably write workflow state without
|
|
28
28
|
* single-writer ownership and without having recovered existing runs. Placed at
|
|
29
29
|
* each public awaited entry so the caller gets a clean {@link EngineLeaseNotHeldError}
|
|
30
|
-
* — without this, fork
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* — without this, fork, resume, and the schedule mutators (`schedule`,
|
|
31
|
+
* `pauseSchedule`, `resumeSchedule`, `cancelSchedule`, and `updateSchedule`) would
|
|
32
|
+
* reach `resolveFenceEpochOrHalt` with no held epoch and be misreported as a
|
|
33
|
+
* deposition (warn + teardown) rather than the true "lease not held yet"
|
|
34
|
+
* condition. A no-op under `ownership: 'none'`.
|
|
33
35
|
*/
|
|
34
36
|
export declare function assertLeaseHeldForEngineWork(internals: EngineInternals): void;
|
|
35
37
|
/**
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type BatchOperation } from '../../storage/interface.ts';
|
|
2
|
+
import type { WorkflowFinalizerStatus, WorkflowState } from '../types.ts';
|
|
3
|
+
import type { EngineInternals } from './internals.ts';
|
|
4
|
+
export interface TeardownSucceededRecord {
|
|
5
|
+
attempts: number;
|
|
6
|
+
completedAt: number;
|
|
7
|
+
workflowExecutionToken?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function buildTeardownSuccessOperations(workflowId: string, attempts: number, completedAt: number, workflowExecutionToken: string | undefined): BatchOperation[];
|
|
10
|
+
export declare function getFinalizerStatus(internals: EngineInternals, workflowId: string, state: WorkflowState | null): Promise<WorkflowFinalizerStatus | null>;
|