@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
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { KEYS } from "../../storage/interface.js";
|
|
2
|
+
import { decode, encode } from "../codec.js";
|
|
3
|
+
import { isRecord } from "../debug-output.js";
|
|
4
|
+
import { isTeardownClaim } from "./state-utilities.js";
|
|
5
|
+
export function buildTeardownSuccessOperations(workflowId, attempts, completedAt, workflowExecutionToken) {
|
|
6
|
+
const outcome = {
|
|
7
|
+
attempts,
|
|
8
|
+
completedAt,
|
|
9
|
+
...workflowExecutionToken === void 0 ? {} : { workflowExecutionToken }
|
|
10
|
+
};
|
|
11
|
+
return [
|
|
12
|
+
{ type: "delete", key: KEYS.teardownOwed(workflowId) },
|
|
13
|
+
{ type: "delete", key: KEYS.finalizerState(workflowId) },
|
|
14
|
+
{ type: "put", key: KEYS.teardownSucceeded(workflowId), value: encode(outcome) }
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
function decodeUnknown(bytes) {
|
|
18
|
+
try {
|
|
19
|
+
return decode(bytes);
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function isNonNegativeSafeInteger(value) {
|
|
25
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
26
|
+
}
|
|
27
|
+
function isNonNegativeFiniteNumber(value) {
|
|
28
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
29
|
+
}
|
|
30
|
+
function recordBelongsToRun(record, state) {
|
|
31
|
+
const recordToken = record.workflowExecutionToken;
|
|
32
|
+
if (recordToken !== void 0 && typeof recordToken !== "string")
|
|
33
|
+
return !1;
|
|
34
|
+
if (state === null)
|
|
35
|
+
return !0;
|
|
36
|
+
return recordToken === state.workflowExecutionToken;
|
|
37
|
+
}
|
|
38
|
+
export async function getFinalizerStatus(internals, workflowId, state) {
|
|
39
|
+
const claimBytes = await internals.storage.get(KEYS.teardownOwed(workflowId)), claimStatus = decodeClaimStatus(claimBytes);
|
|
40
|
+
if (claimStatus !== null)
|
|
41
|
+
return claimStatus;
|
|
42
|
+
const deadLetterBytes = await internals.storage.get(KEYS.teardownDeadLetter(workflowId)), failedStatus = decodeFailedStatus(deadLetterBytes, state);
|
|
43
|
+
if (failedStatus !== null)
|
|
44
|
+
return failedStatus;
|
|
45
|
+
const succeededBytes = await internals.storage.get(KEYS.teardownSucceeded(workflowId));
|
|
46
|
+
return decodeSucceededStatus(succeededBytes, state);
|
|
47
|
+
}
|
|
48
|
+
function decodeClaimStatus(bytes) {
|
|
49
|
+
if (bytes === null)
|
|
50
|
+
return null;
|
|
51
|
+
const claim = decodeUnknown(bytes);
|
|
52
|
+
if (!isTeardownClaim(claim))
|
|
53
|
+
return null;
|
|
54
|
+
if (claim.status === "running" && claim.claimedAt !== void 0)
|
|
55
|
+
return { status: "running", attempts: claim.attempts + 1, startedAt: claim.claimedAt };
|
|
56
|
+
return { status: "pending", attempts: claim.attempts };
|
|
57
|
+
}
|
|
58
|
+
function decodeFailedStatus(bytes, state) {
|
|
59
|
+
if (bytes === null)
|
|
60
|
+
return null;
|
|
61
|
+
const record = decodeUnknown(bytes);
|
|
62
|
+
if (!isRecord(record) || !recordBelongsToRun(record, state) || typeof record.lastError !== "string" || !isNonNegativeSafeInteger(record.attempts) || !isNonNegativeFiniteNumber(record.deadLetteredAt))
|
|
63
|
+
return null;
|
|
64
|
+
return {
|
|
65
|
+
status: "failed",
|
|
66
|
+
attempts: record.attempts,
|
|
67
|
+
failedAt: record.deadLetteredAt,
|
|
68
|
+
error: record.lastError
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function decodeSucceededStatus(bytes, state) {
|
|
72
|
+
if (bytes === null)
|
|
73
|
+
return null;
|
|
74
|
+
const record = decodeUnknown(bytes);
|
|
75
|
+
if (!isRecord(record) || !recordBelongsToRun(record, state) || !isNonNegativeSafeInteger(record.attempts) || !isNonNegativeFiniteNumber(record.completedAt))
|
|
76
|
+
return null;
|
|
77
|
+
return {
|
|
78
|
+
status: "succeeded",
|
|
79
|
+
attempts: record.attempts,
|
|
80
|
+
completedAt: record.completedAt
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -5,7 +5,7 @@ import type { TypedEventTarget, WeftEventMap } from '../events.ts';
|
|
|
5
5
|
import type { Interceptor } from '../interceptor.ts';
|
|
6
6
|
import { type ReviewRequest } from '../review/index.ts';
|
|
7
7
|
import { Scheduler } from '../scheduler.ts';
|
|
8
|
-
import { type AnyActivityDefinition, type AnyWorkflowDefinition, type AttributeFilterKey, type BulkCancelResult, type BulkDeleteResult, type BulkOperationCommitOptions, type BulkOperationDryRunOptions, type BulkOperationDryRunResult, type BulkRetryFailedResult, type BulkSignalAllCommitOptions, type BulkSignalAllDryRunOptions, type BulkSignalResult, type BulkTagResult, type CheckpointState, type CheckpointSummary, type CoordinatedUpdateResult, type DefaultActivityTypes, type DefaultWorkflowRegistry, type ForkOptions, type InferActivityEntries, type InferActivityEntry, type InferWorkflowEntries, type InferWorkflowEntry, type ListFilter, type ListOptions, type PaginatedResult, type PurgeResult, type QueryDefinition, type RegisteredWorkflowDefinition, type RetentionOverview, type ReviewListEntry, type ReviewListFilter, type ScheduleDefinition, type ScheduleFilter, type ScheduleOptions, type ScheduleSpec, type ScheduleSummary, type SearchAttributeValue, type SignalDefinition, type SignalDeliveryOptions, type StartOrSignalOptions, type StartOrSignalSignal, type StartWorkflowOptions, type SubmitReviewOptions, type TypedListFilter, type UpdateDefinition, type WorkflowEvent, type WorkflowInput, type WorkflowOutput, type WorkflowReplay, type WorkflowServices, type WorkflowServicesUnion, type WorkflowState, type WorkflowSummary, type WorkflowTimelineEntry } from '../types.ts';
|
|
8
|
+
import { type AnyActivityDefinition, type AnyWorkflowDefinition, type AttributeFilterKey, type BulkCancelResult, type BulkDeleteResult, type BulkOperationCommitOptions, type BulkOperationDryRunOptions, type BulkOperationDryRunResult, type BulkRetryFailedResult, type BulkSignalAllCommitOptions, type BulkSignalAllDryRunOptions, type BulkSignalResult, type BulkTagResult, type CheckpointState, type CheckpointSummary, type CoordinatedUpdateResult, type DefaultActivityTypes, type DefaultWorkflowRegistry, type ForkOptions, type InferActivityEntries, type InferActivityEntry, type InferWorkflowEntries, type InferWorkflowEntry, type ListFilter, type ListOptions, type PaginatedResult, type PendingAsyncActivityListOptions, type PendingAsyncActivityPage, type PurgeResult, type QueryDefinition, type RegisteredWorkflowDefinition, type RetentionOverview, type ReviewListEntry, type ReviewListFilter, type ScheduleDefinition, type ScheduleFilter, type ScheduleOptions, type ScheduleSpec, type ScheduleSummary, type ScheduleUpdateOptions, type SearchAttributeValue, type SignalDefinition, type SignalDeliveryOptions, type StartOrSignalOptions, type StartOrSignalSignal, type StartWorkflowOptions, type SubmitReviewOptions, type TypedListFilter, type UpdateDefinition, type WorkflowEvent, type WorkflowFinalizerStatus, type WorkflowInput, type WorkflowOutput, type WorkflowReplay, type WorkflowScheduleProvenance, type WorkflowServices, type WorkflowServicesUnion, type WorkflowState, type WorkflowSummary, type WorkflowTimelineEntry } from '../types.ts';
|
|
9
9
|
import type { TimerEntry } from '../types/checkpoint.ts';
|
|
10
10
|
import type { WorkflowAlreadyRegistered } from '../types/workflow-builder.ts';
|
|
11
11
|
import { type AggregateOptions, type AggregateResult } from './aggregate.ts';
|
|
@@ -15,6 +15,7 @@ import type { EngineConstructorOptions } from './engine-internal-types.ts';
|
|
|
15
15
|
import type { EngineStateNamespace } from './engine-state-namespace.ts';
|
|
16
16
|
import { HANDLE_RESULT_PROMISE, WorkflowHandle } from './handles.ts';
|
|
17
17
|
import { ENGINE_LEASE_LOST_WARNING_NAME } from './lease-deposition.ts';
|
|
18
|
+
import type { EngineLeaseHealth } from './lease-health.ts';
|
|
18
19
|
import { type RecoverAllOptions, type StartOrSignalResult } from './lifecycle.ts';
|
|
19
20
|
import { assertCompatiblePersistedDataVersion } from './persisted-data-version.ts';
|
|
20
21
|
import { ScheduleHandle } from './schedule-handle.ts';
|
|
@@ -26,6 +27,7 @@ export type { PendingTimelineEntry, RegistrationEntry, ResolvedOptions, TrackedW
|
|
|
26
27
|
export { ActivityResolutionError, BulkDeleteRequiresTerminalWorkflowsError, BulkOperationConfirmationError, EngineCreateNameMismatchError, EngineDisposedError, IdempotencyKeyPurgedError, PersistedDataIncompatibleError, StartOrSignalConflictError, WorkflowAlreadyExistsError, WorkflowConcurrencyLimitExceededError, WorkflowNotFoundError, WorkflowNotRegisteredError, WorkflowSuspendNotSupportedError, WorkflowTeardownPendingError, WorkflowTypeNotRegisteredForRecoveryError, } from './errors.ts';
|
|
27
28
|
export { HANDLE_RESULT_PROMISE, WorkflowHandle } from './handles.ts';
|
|
28
29
|
export { EngineLeaseAcquisitionTimeoutError, EngineLeaseCorruptedError, EngineLeaseNotHeldError, } from './lease-errors.ts';
|
|
30
|
+
export type { EngineLeaseHealth, LeaseLostReason } from './lease-health.ts';
|
|
29
31
|
export type { RecoverAllOptions, RecoveredWorkflowInfo } from './lifecycle.ts';
|
|
30
32
|
export { ScheduleHandle } from './schedule-handle.ts';
|
|
31
33
|
export type { WorkflowFeedListener, WorkflowFeedRecord, WorkflowFeedSelector, } from './workflow-feed.ts';
|
|
@@ -304,7 +306,7 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
304
306
|
pauseSchedule(scheduleId: string): Promise<void>;
|
|
305
307
|
resumeSchedule(scheduleId: string): Promise<void>;
|
|
306
308
|
cancelSchedule(scheduleId: string): Promise<void>;
|
|
307
|
-
updateSchedule(scheduleId: string, newSpec: string | ScheduleSpec): Promise<void>;
|
|
309
|
+
updateSchedule(scheduleId: string, newSpec: string | ScheduleSpec, options?: ScheduleUpdateOptions): Promise<void>;
|
|
308
310
|
[HANDLE_RESULT_PROMISE](workflowId: string): Promise<unknown>;
|
|
309
311
|
[ENGINE_PARKED_WORKFLOW_COUNT_FOR_TESTING](): number;
|
|
310
312
|
[ENGINE_SIGNAL_WAITER_COUNT_FOR_TESTING](): number;
|
|
@@ -394,6 +396,13 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
394
396
|
* the token (unknown, or already completed/failed — tokens are single-use).
|
|
395
397
|
*/
|
|
396
398
|
completeAsyncActivity(token: string, result: unknown): Promise<void>;
|
|
399
|
+
/**
|
|
400
|
+
* List a bounded page of durable async activities awaiting out-of-band
|
|
401
|
+
* completion for one workflow. This reads storage directly, so callers can
|
|
402
|
+
* recover tokens after a process restart before `recoverAll()` repopulates
|
|
403
|
+
* the in-memory completion map.
|
|
404
|
+
*/
|
|
405
|
+
listPendingAsyncActivities(workflowId: string, options?: PendingAsyncActivityListOptions): Promise<PendingAsyncActivityPage>;
|
|
397
406
|
/**
|
|
398
407
|
* Fail a deferred activity out-of-band with `error`. The error is thrown into
|
|
399
408
|
* the workflow generator at the parked step — identical to an inline activity
|
|
@@ -425,6 +434,21 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
425
434
|
suspend(workflowId: string): Promise<void>;
|
|
426
435
|
timeout(workflowId: string): Promise<void>;
|
|
427
436
|
get(workflowId: string): Promise<WorkflowState | null>;
|
|
437
|
+
/** Return the schedule occurrence that launched a workflow, when applicable. */
|
|
438
|
+
getScheduleProvenance(workflowId: string): Promise<WorkflowScheduleProvenance | null>;
|
|
439
|
+
/** Return durable post-terminal finalizer progress or outcome, when applicable. */
|
|
440
|
+
getFinalizerStatus(workflowId: string): Promise<WorkflowFinalizerStatus | null>;
|
|
441
|
+
/**
|
|
442
|
+
* Return this process's last-known ownership-lease health.
|
|
443
|
+
*
|
|
444
|
+
* This is a synchronous diagnostic snapshot: it never performs a storage read
|
|
445
|
+
* and therefore remains available to operator transports after a confirmed
|
|
446
|
+
* deposition has detached the lease manager. Holder identifiers and timestamps
|
|
447
|
+
* are present only while the manager still has its own last-written holder
|
|
448
|
+
* record; a detached deposed engine reports the confirmed loss without
|
|
449
|
+
* inventing successor details.
|
|
450
|
+
*/
|
|
451
|
+
getLeaseHealth(): EngineLeaseHealth;
|
|
428
452
|
getCurrentCheckpointStep(workflowId: string): Promise<number | null>;
|
|
429
453
|
getAttributes(workflowId: string): Promise<Record<string, SearchAttributeValue> | null>;
|
|
430
454
|
setAttributes(workflowId: string, attributes: Record<string, SearchAttributeValue>): Promise<void>;
|
|
@@ -22,7 +22,10 @@ import {
|
|
|
22
22
|
completeAsyncActivity as completeAsyncActivityFromInternals,
|
|
23
23
|
failAsyncActivity as failAsyncActivityFromInternals
|
|
24
24
|
} from "./async-activity-completion.js";
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
listPendingAsyncActivities as listPendingAsyncActivitiesFromInternals,
|
|
27
|
+
recoverPendingAsyncActivities
|
|
28
|
+
} from "./async-activity-records.js";
|
|
26
29
|
import { broadcast as broadcastFromInternals } from "./broadcast.js";
|
|
27
30
|
import {
|
|
28
31
|
cancelAll as cancelAllWorkflows,
|
|
@@ -81,6 +84,7 @@ import {
|
|
|
81
84
|
} from "./errors.js";
|
|
82
85
|
import { assertLeaseHeldForEngineWork, commitFencedEngineWrite } from "./fenced-write.js";
|
|
83
86
|
import { recordFinalizerState } from "./finalizer-state.js";
|
|
87
|
+
import { getFinalizerStatus as getFinalizerStatusFromInternals } from "./finalizer-status.js";
|
|
84
88
|
import {
|
|
85
89
|
createWorkflowHandleWithResultPromise as createWorkflowHandleWithResultPromiseFromInternals,
|
|
86
90
|
getWorkflowResultPromise as getWorkflowResultPromiseFromInternals
|
|
@@ -134,6 +138,7 @@ import {
|
|
|
134
138
|
submitReview as submitReviewFromInternals
|
|
135
139
|
} from "./reviews.js";
|
|
136
140
|
import { ScheduleHandle } from "./schedule-handle.js";
|
|
141
|
+
import { decodeScheduleRunMetadata } from "./schedule-run-metadata.js";
|
|
137
142
|
import {
|
|
138
143
|
cancelSchedule as cancelScheduleFromInternals,
|
|
139
144
|
listSchedules as listSchedulesFromInternals,
|
|
@@ -306,9 +311,12 @@ export class Engine extends EventTarget {
|
|
|
306
311
|
getInternals(this).pendingNestingDepth = void 0;
|
|
307
312
|
getInternals(this).pendingParentHeaders = void 0;
|
|
308
313
|
getInternals(this).pendingExecutionStateOwnerId = void 0;
|
|
314
|
+
getInternals(this).pendingParentWorkflowId = void 0;
|
|
315
|
+
getInternals(this).pendingParentWorkflowExecutionToken = void 0;
|
|
309
316
|
getInternals(this).workflowNestingDepths = new Map;
|
|
310
317
|
getInternals(this).workflowHeaders = new Map;
|
|
311
318
|
getInternals(this).workflowStateWriteChains = new Map;
|
|
319
|
+
getInternals(this).scheduleStateOperationChains = new Map;
|
|
312
320
|
getInternals(this).finalizationRegistry = new FinalizationRegistry(createHandleCacheFinalizer(getInternals(this).handleCache));
|
|
313
321
|
getInternals(this).options = resolvedOptions;
|
|
314
322
|
getInternals(this).scheduler = new Scheduler({
|
|
@@ -641,11 +649,13 @@ export class Engine extends EventTarget {
|
|
|
641
649
|
return untagAllWorkflows(getInternals(this), filter, tags, options);
|
|
642
650
|
}
|
|
643
651
|
async schedule(typeOrDefinition, input, spec, options) {
|
|
652
|
+
const internals = getInternals(this);
|
|
653
|
+
assertLeaseHeldForEngineWork(internals);
|
|
644
654
|
if (typeof typeOrDefinition === "object")
|
|
645
|
-
return scheduleDefinitionFromInternals(
|
|
655
|
+
return scheduleDefinitionFromInternals(internals, typeOrDefinition);
|
|
646
656
|
if (spec === void 0)
|
|
647
657
|
throw Error("A cron string or schedule spec must be provided when scheduling by workflow type.");
|
|
648
|
-
return scheduleFromInternals(
|
|
658
|
+
return scheduleFromInternals(internals, typeOrDefinition, input, spec, options);
|
|
649
659
|
}
|
|
650
660
|
async getSchedule(scheduleId) {
|
|
651
661
|
const normalizedScheduleId = coerceScheduleId(scheduleId, "scheduleId"), state = await loadScheduleState(getInternals(this), normalizedScheduleId);
|
|
@@ -655,16 +665,24 @@ export class Engine extends EventTarget {
|
|
|
655
665
|
return listSchedulesFromInternals(getInternals(this), filter);
|
|
656
666
|
}
|
|
657
667
|
async pauseSchedule(scheduleId) {
|
|
658
|
-
|
|
668
|
+
const internals = getInternals(this);
|
|
669
|
+
assertLeaseHeldForEngineWork(internals);
|
|
670
|
+
return pauseScheduleFromInternals(internals, scheduleId);
|
|
659
671
|
}
|
|
660
672
|
async resumeSchedule(scheduleId) {
|
|
661
|
-
|
|
673
|
+
const internals = getInternals(this);
|
|
674
|
+
assertLeaseHeldForEngineWork(internals);
|
|
675
|
+
return resumeScheduleFromInternals(internals, scheduleId);
|
|
662
676
|
}
|
|
663
677
|
async cancelSchedule(scheduleId) {
|
|
664
|
-
|
|
678
|
+
const internals = getInternals(this);
|
|
679
|
+
assertLeaseHeldForEngineWork(internals);
|
|
680
|
+
return cancelScheduleFromInternals(internals, scheduleId);
|
|
665
681
|
}
|
|
666
|
-
async updateSchedule(scheduleId, newSpec) {
|
|
667
|
-
|
|
682
|
+
async updateSchedule(scheduleId, newSpec, options) {
|
|
683
|
+
const internals = getInternals(this);
|
|
684
|
+
assertLeaseHeldForEngineWork(internals);
|
|
685
|
+
return updateScheduleFromInternals(internals, scheduleId, newSpec, options);
|
|
668
686
|
}
|
|
669
687
|
[HANDLE_RESULT_PROMISE](workflowId) {
|
|
670
688
|
return getWorkflowResultPromiseFromInternals(getInternals(this), workflowId);
|
|
@@ -721,6 +739,9 @@ export class Engine extends EventTarget {
|
|
|
721
739
|
finalizeTimeline: (workflowId, status, output) => finalizePendingTimelineEntry(getInternals(this), workflowId, status, output)
|
|
722
740
|
});
|
|
723
741
|
}
|
|
742
|
+
async listPendingAsyncActivities(workflowId, options) {
|
|
743
|
+
return listPendingAsyncActivitiesFromInternals(getInternals(this), workflowId, options);
|
|
744
|
+
}
|
|
724
745
|
async failAsyncActivity(token, error) {
|
|
725
746
|
await failAsyncActivityFromInternals(getInternals(this), token, error, {
|
|
726
747
|
feedOperationResult: (workflowId, outcome, originalReason) => feedOperationResult(getInternals(this), workflowId, outcome, originalReason),
|
|
@@ -742,6 +763,48 @@ export class Engine extends EventTarget {
|
|
|
742
763
|
return { ...state, status: "pending" };
|
|
743
764
|
return state;
|
|
744
765
|
}
|
|
766
|
+
async getScheduleProvenance(workflowId) {
|
|
767
|
+
const bytes = await getInternals(this).storage.get(KEYS.scheduleRunLink(workflowId));
|
|
768
|
+
if (bytes === null)
|
|
769
|
+
return null;
|
|
770
|
+
const metadata = decodeScheduleRunMetadata(bytes);
|
|
771
|
+
if (metadata === null)
|
|
772
|
+
return null;
|
|
773
|
+
return {
|
|
774
|
+
scheduleId: metadata.id,
|
|
775
|
+
...metadata.occurrence === void 0 ? {} : { occurrence: metadata.occurrence }
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
async getFinalizerStatus(workflowId) {
|
|
779
|
+
const internals = getInternals(this), state = await loadWorkflowState(internals, workflowId);
|
|
780
|
+
return getFinalizerStatusFromInternals(internals, workflowId, state);
|
|
781
|
+
}
|
|
782
|
+
getLeaseHealth() {
|
|
783
|
+
const internals = getInternals(this);
|
|
784
|
+
if (internals.options.ownershipMode === "none")
|
|
785
|
+
return { mode: "none", status: "disabled", holdsLease: !1 };
|
|
786
|
+
if (internals.deposed) {
|
|
787
|
+
const lastKnownLease = internals.leaseManager?.health();
|
|
788
|
+
if (lastKnownLease !== void 0 && lastKnownLease.status !== "no-lease")
|
|
789
|
+
return {
|
|
790
|
+
mode: "lease",
|
|
791
|
+
...lastKnownLease,
|
|
792
|
+
status: "contested",
|
|
793
|
+
holdsLease: !1,
|
|
794
|
+
lossReason: "deposed"
|
|
795
|
+
};
|
|
796
|
+
return {
|
|
797
|
+
mode: "lease",
|
|
798
|
+
status: "contested",
|
|
799
|
+
holdsLease: !1,
|
|
800
|
+
lossReason: "deposed"
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
return {
|
|
804
|
+
mode: "lease",
|
|
805
|
+
...internals.leaseManager?.health() ?? { status: "no-lease", holdsLease: !1 }
|
|
806
|
+
};
|
|
807
|
+
}
|
|
745
808
|
async getCurrentCheckpointStep(workflowId) {
|
|
746
809
|
const inMemory = getInternals(this).checkpoints.get(workflowId);
|
|
747
810
|
if (inMemory !== void 0)
|
|
@@ -175,9 +175,12 @@ export interface EngineInternals {
|
|
|
175
175
|
pendingNestingDepth: number | undefined;
|
|
176
176
|
pendingParentHeaders: Map<string, string> | undefined;
|
|
177
177
|
pendingExecutionStateOwnerId: string | null | undefined;
|
|
178
|
+
pendingParentWorkflowId: string | undefined;
|
|
179
|
+
pendingParentWorkflowExecutionToken: string | undefined;
|
|
178
180
|
workflowNestingDepths: Map<string, number>;
|
|
179
181
|
workflowHeaders: Map<string, Map<string, string>>;
|
|
180
182
|
workflowStateWriteChains: Map<string, Promise<void>>;
|
|
183
|
+
scheduleStateOperationChains: Map<string, Promise<void>>;
|
|
181
184
|
heartbeatDetails: Map<string, unknown>;
|
|
182
185
|
/**
|
|
183
186
|
* Last heartbeat payload PER ACTIVITY STEP, so a retry of a step can read the
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why a holder lost its lease while running. `deposed` is confirmed ownership
|
|
3
|
+
* loss; `renewal-unconfirmable` means storage failures outlasted the last
|
|
4
|
+
* confirmed lease expiry.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import type { LeaseLostReason } from '@lostgradient/weft';
|
|
9
|
+
*
|
|
10
|
+
* function requiresImmediateHandoff(reason: LeaseLostReason): boolean {
|
|
11
|
+
* return reason === 'deposed';
|
|
12
|
+
* }
|
|
13
|
+
* void requiresImmediateHandoff;
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export type LeaseLostReason = 'deposed' | 'renewal-unconfirmable';
|
|
17
|
+
/** Process-local, last-known ownership state exposed through the operator API. */
|
|
18
|
+
export type LeaseManagerHealth = {
|
|
19
|
+
status: 'no-lease';
|
|
20
|
+
holdsLease: false;
|
|
21
|
+
} | {
|
|
22
|
+
status: 'healthy';
|
|
23
|
+
holdsLease: true;
|
|
24
|
+
holderId: string;
|
|
25
|
+
heldSince: number;
|
|
26
|
+
expiresAt: number;
|
|
27
|
+
lastRenewedAt: number;
|
|
28
|
+
fencingEpoch: number;
|
|
29
|
+
} | {
|
|
30
|
+
status: 'contested';
|
|
31
|
+
holdsLease: false;
|
|
32
|
+
lossReason?: LeaseLostReason;
|
|
33
|
+
holderId: string;
|
|
34
|
+
heldSince: number;
|
|
35
|
+
expiresAt: number;
|
|
36
|
+
lastRenewedAt: number;
|
|
37
|
+
fencingEpoch: number;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Public engine ownership-health snapshot returned by
|
|
41
|
+
* {@link Engine.getLeaseHealth} and `weft.system.lease`.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import type { EngineLeaseHealth } from '@lostgradient/weft';
|
|
46
|
+
*
|
|
47
|
+
* function needsOperatorAttention(health: EngineLeaseHealth): boolean {
|
|
48
|
+
* return health.status === 'contested';
|
|
49
|
+
* }
|
|
50
|
+
* void needsOperatorAttention;
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export type EngineLeaseHealth = {
|
|
54
|
+
mode: 'none';
|
|
55
|
+
status: 'disabled';
|
|
56
|
+
holdsLease: false;
|
|
57
|
+
} | ({
|
|
58
|
+
mode: 'lease';
|
|
59
|
+
} & LeaseManagerHealth) | {
|
|
60
|
+
mode: 'lease';
|
|
61
|
+
status: 'contested';
|
|
62
|
+
holdsLease: false;
|
|
63
|
+
lossReason: 'deposed';
|
|
64
|
+
};
|
|
File without changes
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
* @module core/engine/lease-manager
|
|
45
45
|
*/
|
|
46
46
|
import { type Storage } from '../../storage/interface.ts';
|
|
47
|
-
|
|
48
|
-
export type LeaseLostReason
|
|
47
|
+
import type { LeaseLostReason, LeaseManagerHealth } from './lease-health.ts';
|
|
48
|
+
export type { LeaseLostReason } from './lease-health.ts';
|
|
49
49
|
/** Options for {@link createLeaseManager}. */
|
|
50
50
|
export type LeaseManagerOptions = {
|
|
51
51
|
storage: Storage;
|
|
@@ -102,6 +102,8 @@ export type LeaseManager = {
|
|
|
102
102
|
startRenewal(): void;
|
|
103
103
|
renewOnce(): Promise<void>;
|
|
104
104
|
currentEpochBytes(): Uint8Array | null;
|
|
105
|
+
/** Return a defensive, synchronous view of this process's last-known lease state. */
|
|
106
|
+
health(): LeaseManagerHealth;
|
|
105
107
|
release(): Promise<void>;
|
|
106
108
|
stop(): void;
|
|
107
109
|
};
|
|
@@ -9,12 +9,13 @@ import { EngineLeaseAcquisitionTimeoutError, EngineLeaseCorruptedError } from ".
|
|
|
9
9
|
const DEFAULT_ACQUIRE_POLL_INTERVAL_MS = 1000;
|
|
10
10
|
export function createLeaseManager(options) {
|
|
11
11
|
const { storage, holderId, getNow, ttlMs, renewIntervalMs, waitTimeoutMs } = options, acquirePollIntervalMs = options.acquirePollIntervalMs ?? DEFAULT_ACQUIRE_POLL_INTERVAL_MS;
|
|
12
|
-
let stopped = !1, heldEpoch = null, heldEpochBytes = null, lastHolderBytes = null, renewalInterval = null, leaseLost = !1, inFlightRenewal = null;
|
|
12
|
+
let stopped = !1, heldEpoch = null, heldEpochBytes = null, lastHolderBytes = null, renewalInterval = null, leaseLost = !1, leaseLostReason = null, heldSince = null, lastRenewedAt = null, inFlightRenewal = null;
|
|
13
13
|
const delay = options.delay ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
14
14
|
function reportLeaseLost(reason) {
|
|
15
15
|
if (leaseLost)
|
|
16
16
|
return;
|
|
17
17
|
leaseLost = !0;
|
|
18
|
+
leaseLostReason = reason;
|
|
18
19
|
options.onLeaseLost?.(reason);
|
|
19
20
|
}
|
|
20
21
|
async function readState() {
|
|
@@ -27,7 +28,7 @@ export function createLeaseManager(options) {
|
|
|
27
28
|
};
|
|
28
29
|
}
|
|
29
30
|
async function takeOwnership(expectedEpochBytes, expectedHolderBytes, nextEpoch) {
|
|
30
|
-
const
|
|
31
|
+
const acquiredAt = getNow(), expiresAt = acquiredAt + ttlMs, holderBytes = encodeHolder({ holderId, expiresAt, epoch: nextEpoch }), committed = await storageConditionalBatch(storage, [
|
|
31
32
|
{ key: KEYS.leaseEpoch(), expectedValue: expectedEpochBytes },
|
|
32
33
|
{ key: KEYS.leaseHolder(), expectedValue: expectedHolderBytes }
|
|
33
34
|
], [
|
|
@@ -38,6 +39,8 @@ export function createLeaseManager(options) {
|
|
|
38
39
|
heldEpoch = nextEpoch;
|
|
39
40
|
heldEpochBytes = encodeEpoch(nextEpoch);
|
|
40
41
|
lastHolderBytes = holderBytes;
|
|
42
|
+
heldSince = acquiredAt;
|
|
43
|
+
lastRenewedAt = acquiredAt;
|
|
41
44
|
}
|
|
42
45
|
return committed;
|
|
43
46
|
}
|
|
@@ -75,7 +78,7 @@ export function createLeaseManager(options) {
|
|
|
75
78
|
async function renewOnce() {
|
|
76
79
|
if (stopped || leaseLost || heldEpoch === null || lastHolderBytes === null)
|
|
77
80
|
return;
|
|
78
|
-
const
|
|
81
|
+
const renewedAt = getNow(), expiresAt = renewedAt + ttlMs, holderBytes = encodeHolder({ holderId, expiresAt, epoch: heldEpoch });
|
|
79
82
|
let committed;
|
|
80
83
|
try {
|
|
81
84
|
committed = await storageConditionalBatch(storage, [{ key: KEYS.leaseHolder(), expectedValue: lastHolderBytes }], [{ type: "put", key: KEYS.leaseHolder(), value: holderBytes }]);
|
|
@@ -87,6 +90,7 @@ export function createLeaseManager(options) {
|
|
|
87
90
|
}
|
|
88
91
|
if (committed) {
|
|
89
92
|
lastHolderBytes = holderBytes;
|
|
93
|
+
lastRenewedAt = renewedAt;
|
|
90
94
|
return;
|
|
91
95
|
}
|
|
92
96
|
reportLeaseLost("deposed");
|
|
@@ -109,6 +113,30 @@ export function createLeaseManager(options) {
|
|
|
109
113
|
function currentEpochBytes() {
|
|
110
114
|
return heldEpochBytes === null ? null : heldEpochBytes.slice();
|
|
111
115
|
}
|
|
116
|
+
function health() {
|
|
117
|
+
if (stopped)
|
|
118
|
+
return { status: "no-lease", holdsLease: !1 };
|
|
119
|
+
const holder = lastHolderBytes === null ? null : decodeHolder(lastHolderBytes);
|
|
120
|
+
if (holder === null || heldEpoch === null || heldSince === null || lastRenewedAt === null)
|
|
121
|
+
return { status: "no-lease", holdsLease: !1 };
|
|
122
|
+
const lastKnownLease = {
|
|
123
|
+
holderId: holder.holderId,
|
|
124
|
+
heldSince,
|
|
125
|
+
expiresAt: holder.expiresAt,
|
|
126
|
+
lastRenewedAt,
|
|
127
|
+
fencingEpoch: heldEpoch
|
|
128
|
+
};
|
|
129
|
+
if (leaseLostReason !== null)
|
|
130
|
+
return {
|
|
131
|
+
status: "contested",
|
|
132
|
+
holdsLease: !1,
|
|
133
|
+
lossReason: leaseLostReason,
|
|
134
|
+
...lastKnownLease
|
|
135
|
+
};
|
|
136
|
+
if (getNow() >= holder.expiresAt)
|
|
137
|
+
return { status: "contested", holdsLease: !1, ...lastKnownLease };
|
|
138
|
+
return { status: "healthy", holdsLease: !0, ...lastKnownLease };
|
|
139
|
+
}
|
|
112
140
|
function clearRenewal() {
|
|
113
141
|
if (renewalInterval !== null) {
|
|
114
142
|
clearInterval(renewalInterval);
|
|
@@ -131,5 +159,5 @@ export function createLeaseManager(options) {
|
|
|
131
159
|
stopped = !0;
|
|
132
160
|
clearRenewal();
|
|
133
161
|
}
|
|
134
|
-
return { acquire, startRenewal, renewOnce, currentEpochBytes, release, stop };
|
|
162
|
+
return { acquire, startRenewal, renewOnce, currentEpochBytes, health, release, stop };
|
|
135
163
|
}
|
|
@@ -80,7 +80,5 @@ async function scheduleFromWorkflowState(internals, state) {
|
|
|
80
80
|
return metadata;
|
|
81
81
|
if (metadata.occurrence !== void 0 && scheduleState.nextFireAt === metadata.occurrence)
|
|
82
82
|
return metadata;
|
|
83
|
-
if (metadata.occurrence === void 0 && scheduleState.overlap === "queue" && scheduleState.queuedRuns > 0)
|
|
84
|
-
return metadata;
|
|
85
83
|
return null;
|
|
86
84
|
}
|
|
@@ -58,19 +58,22 @@ export type RecoverAllOptions = {
|
|
|
58
58
|
*/
|
|
59
59
|
onRecoveredWorkflow?: (info: RecoveredWorkflowInfo) => void | Promise<void>;
|
|
60
60
|
/**
|
|
61
|
-
* Policy for a recovered workflow whose
|
|
62
|
-
*
|
|
63
|
-
* {@link WorkflowDefinition.version}.
|
|
64
|
-
*
|
|
65
|
-
*
|
|
61
|
+
* Policy for a recovered workflow whose persisted
|
|
62
|
+
* {@link WorkflowVersionTuple} or checkpoint `version` no longer matches the
|
|
63
|
+
* registered {@link WorkflowDefinition.version}. Recovery checks both
|
|
64
|
+
* persisted records against the registered version so current workflow-state
|
|
65
|
+
* metadata cannot mask a stale checkpoint version. The mismatch is detected
|
|
66
|
+
* before `resolveWorkflowServices` and `onRecoveredWorkflow` run for that
|
|
67
|
+
* workflow, so a mismatched run never re-provides services or invokes the
|
|
68
|
+
* hook.
|
|
66
69
|
*
|
|
67
70
|
* - `'fail-run'` (default): fail only the mismatched run to a terminal
|
|
68
71
|
* `failed` state with a `system` failure category carrying the
|
|
69
72
|
* {@link VersionMismatchError} message, then continue recovering its
|
|
70
73
|
* siblings. The run never advances user workflow code.
|
|
71
|
-
* - `'throw'`:
|
|
72
|
-
* {@link VersionMismatchError} out of `recoverAll()` immediately,
|
|
73
|
-
*
|
|
74
|
+
* - `'throw'`: use fail-fast recovery — rethrow the
|
|
75
|
+
* {@link VersionMismatchError} out of `recoverAll()` immediately, leaving
|
|
76
|
+
* every workflow not yet processed in this batch unresumed.
|
|
74
77
|
*/
|
|
75
78
|
versionMismatchPolicy?: 'fail-run' | 'throw';
|
|
76
79
|
};
|
|
@@ -19,6 +19,7 @@ export function buildStartBatchOperations(_internals, workflowId, state, checkpo
|
|
|
19
19
|
},
|
|
20
20
|
...visibilityIndexOperations,
|
|
21
21
|
...buildWorkflowTagIndexOperations(workflowId, void 0, state.tags),
|
|
22
|
+
...buildChildWorkflowIndexOperations(state),
|
|
22
23
|
...buildInitialSearchAttributeOperations(_internals, workflowId, registration, options?.searchAttributes, callbacks),
|
|
23
24
|
...buildPerRunScratchOperations(workflowId, options, workflowStartHeaders),
|
|
24
25
|
...additionalOperations ?? []
|
|
@@ -34,6 +35,17 @@ export function buildStartBatchOperations(_internals, workflowId, state, checkpo
|
|
|
34
35
|
operations.push(...buildTimerBatchOperations(delayedStartTimer));
|
|
35
36
|
return operations;
|
|
36
37
|
}
|
|
38
|
+
function buildChildWorkflowIndexOperations(state) {
|
|
39
|
+
if (state.parentWorkflowId === void 0)
|
|
40
|
+
return [];
|
|
41
|
+
return [
|
|
42
|
+
{
|
|
43
|
+
type: "put",
|
|
44
|
+
key: KEYS.childWorkflowByParent(state.parentWorkflowId, state.parentWorkflowExecutionToken, state.id),
|
|
45
|
+
value: EMPTY_STORAGE_VALUE
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
}
|
|
37
49
|
function buildPerRunScratchOperations(workflowId, options, workflowStartHeaders) {
|
|
38
50
|
const hasHeaders = workflowStartHeaders !== void 0 && workflowStartHeaders.size > 0, hasServices = options?.services !== void 0, operations = [];
|
|
39
51
|
if (hasHeaders)
|
|
@@ -9,5 +9,5 @@ export declare function start(internals: EngineInternals, type: string, input: u
|
|
|
9
9
|
export declare function startWorkflow(internals: EngineInternals, type: string, input: unknown, options: StartWorkflowOptions | undefined, additionalStartOperations: BatchOperation[] | undefined, callbacks: LifecycleCallbacks, buildIdempotentStartOperations?: BuildIdempotentStartOperations): Promise<WorkflowHandle>;
|
|
10
10
|
export declare function resolveScheduledStartAt(internals: EngineInternals, options: StartOptions | undefined, submissionTime: number, callbacks: LifecycleCallbacks): number | undefined;
|
|
11
11
|
export declare function parseStartOptionDuration(_internals: EngineInternals, duration: Duration, fieldName: 'options.executionTimeout' | 'options.startAfter', _callbacks: LifecycleCallbacks): number;
|
|
12
|
-
export declare function createInitialWorkflowState(internals: EngineInternals, workflowId: string, type: string, input: unknown, versionTuple: WorkflowVersionTuple, options: StartOptions | undefined, tags: string[] | undefined, executionStateOwnerId: string | undefined, delayedStartTimer: TimerEntry | undefined, callbacks: LifecycleCallbacks): WorkflowState;
|
|
12
|
+
export declare function createInitialWorkflowState(internals: EngineInternals, workflowId: string, type: string, input: unknown, versionTuple: WorkflowVersionTuple, options: StartOptions | undefined, tags: string[] | undefined, executionStateOwnerId: string | undefined, parentWorkflowId: string | undefined, parentWorkflowExecutionToken: string | undefined, delayedStartTimer: TimerEntry | undefined, callbacks: LifecycleCallbacks): WorkflowState;
|
|
13
13
|
export declare function createInitialCheckpoint(internals: EngineInternals, workflowId: string, workflowVersion: string, options: StartOptions | undefined, _callbacks: LifecycleCallbacks): Checkpoint;
|