@lostgradient/weft 0.11.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 +5167 -0
- package/dist/cli/generated/operation-client.generated.d.ts +119 -10
- package/dist/cli/generated/operation-client.generated.js +74 -1
- package/dist/cli/index.js +1 -0
- 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/cli-main.js +227 -401
- 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 +84 -2
- package/dist/client/http-request.d.ts +35 -6
- package/dist/client/http-request.js +31 -10
- 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 +6 -0
- package/dist/client/index.js +18 -0
- 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/connection.d.ts +8 -0
- package/dist/connection.js +41 -17
- 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-core.js +2 -1
- 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 +69 -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 +28 -0
- 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/lifecycle/transition.js +19 -9
- 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/definition-schema-to-json.d.ts +11 -0
- package/dist/core/types/definition-schema-to-json.js +11 -2
- 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 -0
- package/dist/index.d.ts +4 -3
- package/dist/indexeddb.js +1 -0
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +63 -61
- package/dist/mcp/http.d.ts +7 -2
- package/dist/mcp/session.d.ts +3 -3
- package/dist/mcp/session.js +3 -2
- package/dist/mcp/stdio.d.ts +7 -2
- package/dist/observability/index.js +2 -2
- package/dist/runtime/portable.d.ts +33 -0
- package/dist/runtime/portable.js +17 -6
- package/dist/server/access-policy-metadata.d.ts +92 -0
- package/dist/server/access-policy-metadata.js +78 -0
- package/dist/server/engine-event-feed-backend.d.ts +22 -3
- package/dist/server/fault-to-http.d.ts +3 -7
- package/dist/server/fault-to-http.js +2 -34
- package/dist/server/fleet-event-feed.d.ts +65 -0
- package/dist/server/handler/index.d.ts +11 -2
- package/dist/server/handler/index.js +8 -1
- package/dist/server/handler/route-dispatch.d.ts +10 -3
- package/dist/server/handler/route-dispatch.js +19 -4
- package/dist/server/handler.js +1 -56
- package/dist/server/index.d.ts +13 -2
- package/dist/server/index.js +88 -64
- 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/submit-review-decision.d.ts +2 -0
- package/dist/server/operations/submit-review-decision.js +19 -2
- 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/replay-live-feed-internals.d.ts +19 -0
- package/dist/server/replay-live-feed-internals.js +76 -0
- 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/runtime/authentication-bridge.d.ts +2 -2
- package/dist/server/serve-internals.js +3 -3
- package/dist/server/task-queue.d.ts +7 -5
- package/dist/server/workflow-event-feed.d.ts +100 -11
- package/dist/server/workflow-event-feed.js +1 -140
- package/dist/service-worker/index.d.ts +8 -2
- package/dist/service-worker/index.js +37 -56
- package/dist/service-worker/setup.d.ts +6 -2
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +3 -3
- package/dist/storage/capabilities.d.ts +1 -1
- package/dist/storage/cloudflare-durable-object-sql.d.ts +75 -0
- package/dist/storage/cloudflare-durable-object-sql.js +0 -0
- package/dist/storage/cloudflare-value-codec.d.ts +67 -0
- package/dist/storage/cloudflare-value-codec.js +46 -0
- package/dist/storage/cloudflare.d.ts +140 -0
- package/dist/storage/cloudflare.js +127 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/http.js +200 -2
- package/dist/storage/index.d.ts +8 -1
- package/dist/storage/indexeddb.js +311 -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/node-sqlite.js +3 -3
- package/dist/storage/postgres-key-value-queries.d.ts +6 -0
- package/dist/storage/postgres-key-value-queries.js +2 -3
- 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/sql-identifier.d.ts +35 -0
- package/dist/storage/sql-identifier.js +5 -0
- package/dist/storage/sqlite-key-value-queries.d.ts +11 -6
- package/dist/storage/sqlite-key-value-queries.js +3 -3
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/storage/typed-storage.js +138 -2
- package/dist/storage/web-extension.js +298 -1
- package/dist/testing/index.js +21 -60
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -0
- package/dist/worker/protocol.js +1 -1
- package/package.json +8 -3
|
@@ -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
|
}
|
|
@@ -57,6 +57,25 @@ export type RecoverAllOptions = {
|
|
|
57
57
|
* recovery continues with its siblings.
|
|
58
58
|
*/
|
|
59
59
|
onRecoveredWorkflow?: (info: RecoveredWorkflowInfo) => void | Promise<void>;
|
|
60
|
+
/**
|
|
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.
|
|
69
|
+
*
|
|
70
|
+
* - `'fail-run'` (default): fail only the mismatched run to a terminal
|
|
71
|
+
* `failed` state with a `system` failure category carrying the
|
|
72
|
+
* {@link VersionMismatchError} message, then continue recovering its
|
|
73
|
+
* siblings. The run never advances user workflow code.
|
|
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.
|
|
77
|
+
*/
|
|
78
|
+
versionMismatchPolicy?: 'fail-run' | 'throw';
|
|
60
79
|
};
|
|
61
80
|
export type LifecycleCallbacks = {
|
|
62
81
|
dispatchEvent: (event: Event) => void;
|
|
@@ -97,6 +116,15 @@ export type LifecycleCallbacks = {
|
|
|
97
116
|
* other workflows from the same storage backend.
|
|
98
117
|
*/
|
|
99
118
|
failWorkflowForCheckpointDecodeError: (workflowId: string, error: Error) => Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Force a recovered workflow to a terminal `failed` state because its
|
|
121
|
+
* persisted version metadata no longer matches the registered
|
|
122
|
+
* `WorkflowDefinition.version` (a {@link VersionMismatchError}). Fails just
|
|
123
|
+
* this run with a `system` failure category so `recoverAll()` can continue
|
|
124
|
+
* recovering other workflows under the default `'fail-run'`
|
|
125
|
+
* {@link RecoverAllOptions.versionMismatchPolicy}.
|
|
126
|
+
*/
|
|
127
|
+
failWorkflowForVersionMismatch: (workflowId: string, error: Error) => Promise<void>;
|
|
100
128
|
};
|
|
101
129
|
/**
|
|
102
130
|
* Pre-replay history circuit breaker. Called at every restore-from-checkpoint
|
|
@@ -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;
|
|
@@ -38,6 +38,10 @@ function prepareStartWorkflow(internals, options, callbacks) {
|
|
|
38
38
|
internals.pendingParentHeaders = void 0;
|
|
39
39
|
const pendingExecutionStateOwnerId = internals.pendingExecutionStateOwnerId, executionStateOwnerId = pendingExecutionStateOwnerId === null ? void 0 : pendingExecutionStateOwnerId ?? workflowId;
|
|
40
40
|
internals.pendingExecutionStateOwnerId = void 0;
|
|
41
|
+
const parentWorkflowId = internals.pendingParentWorkflowId;
|
|
42
|
+
internals.pendingParentWorkflowId = void 0;
|
|
43
|
+
const parentWorkflowExecutionToken = internals.pendingParentWorkflowExecutionToken;
|
|
44
|
+
internals.pendingParentWorkflowExecutionToken = void 0;
|
|
41
45
|
const submissionTime = internals.options.getNow(), scheduledStartAt = resolveScheduledStartAt(internals, options, submissionTime, callbacks), normalizedTags = normalizeStartWorkflowTags(internals, options?.tags, void 0, callbacks), delayedStartTimer = scheduledStartAt !== void 0 && scheduledStartAt > submissionTime ? createDelayedStartTimerEntry(internals, workflowId, scheduledStartAt, options, {
|
|
42
46
|
parseStartOptionDuration: (value, fieldName) => parseStartOptionDuration(internals, value, fieldName, callbacks)
|
|
43
47
|
}) : void 0;
|
|
@@ -46,6 +50,8 @@ function prepareStartWorkflow(internals, options, callbacks) {
|
|
|
46
50
|
callerProvidedId,
|
|
47
51
|
parentHeaders,
|
|
48
52
|
executionStateOwnerId,
|
|
53
|
+
parentWorkflowId,
|
|
54
|
+
parentWorkflowExecutionToken,
|
|
49
55
|
submissionTime,
|
|
50
56
|
delayedStartTimer,
|
|
51
57
|
normalizedTags
|
|
@@ -70,7 +76,15 @@ export async function startWorkflow(internals, type, input, options, additionalS
|
|
|
70
76
|
const workflowConcurrency = registration.concurrency;
|
|
71
77
|
assertServicesSupportedForMode(internals, options);
|
|
72
78
|
assertValidOnTerminalConflict(options);
|
|
73
|
-
const preparation = prepareStartWorkflow(internals, options, callbacks), {
|
|
79
|
+
const preparation = prepareStartWorkflow(internals, options, callbacks), {
|
|
80
|
+
workflowId,
|
|
81
|
+
callerProvidedId,
|
|
82
|
+
parentHeaders,
|
|
83
|
+
executionStateOwnerId,
|
|
84
|
+
parentWorkflowId,
|
|
85
|
+
parentWorkflowExecutionToken,
|
|
86
|
+
delayedStartTimer
|
|
87
|
+
} = preparation;
|
|
74
88
|
assertDeferSupported(internals, options, Boolean(delayedStartTimer));
|
|
75
89
|
if (internals.pendingStarts.has(workflowId))
|
|
76
90
|
throw new WorkflowAlreadyExistsError(workflowId);
|
|
@@ -79,7 +93,9 @@ export async function startWorkflow(internals, type, input, options, additionalS
|
|
|
79
93
|
try {
|
|
80
94
|
const terminalRunToPurge = callerProvidedId ? await resolveTerminalConflictForRestart(internals, workflowId, options) : null;
|
|
81
95
|
assertPayloadWithinLimit(input, internals.options.payloadSizePolicy.maxBytes, "workflow input");
|
|
82
|
-
const versionTuple = createWorkflowVersionTuple(internals, registration, callbacks), state = createInitialWorkflowState(internals, workflowId, type, input, versionTuple, options, preparation.normalizedTags, executionStateOwnerId,
|
|
96
|
+
const versionTuple = createWorkflowVersionTuple(internals, registration, callbacks), state = createInitialWorkflowState(internals, workflowId, type, input, versionTuple, options, preparation.normalizedTags, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken, delayedStartTimer, callbacks);
|
|
97
|
+
applyRestartLineage(state, terminalRunToPurge);
|
|
98
|
+
const checkpoint = createInitialCheckpoint(internals, workflowId, versionTuple.workflowVersion, options, callbacks), workflowStartHeaders = runWorkflowStartInterceptor(internals, workflowId, type, input, parentHeaders, callbacks), persistedWorkflowStartHeaders = selectPersistedWorkflowStartHeaders(workflowStartHeaders), purgeDeleteOperations = terminalRunToPurge !== null ? await prepareTerminalRunPurge(internals, terminalRunToPurge, callbacks) : void 0;
|
|
83
99
|
internals.checkpoints.set(workflowId, checkpoint);
|
|
84
100
|
setWorkflowStartHeaders(internals, workflowId, workflowStartHeaders, callbacks);
|
|
85
101
|
internals.workflowVersionTuples.set(workflowId, versionTuple);
|
|
@@ -121,6 +137,17 @@ export async function startWorkflow(internals, type, input, options, additionalS
|
|
|
121
137
|
rollbackTransientStartState(internals, workflowId);
|
|
122
138
|
}
|
|
123
139
|
}
|
|
140
|
+
function applyRestartLineage(state, displacedState) {
|
|
141
|
+
if (displacedState === null)
|
|
142
|
+
return;
|
|
143
|
+
state.restartedFrom = {
|
|
144
|
+
workflowId: displacedState.id,
|
|
145
|
+
...displacedState.workflowExecutionToken !== void 0 && {
|
|
146
|
+
workflowExecutionToken: displacedState.workflowExecutionToken
|
|
147
|
+
},
|
|
148
|
+
replacedAt: state.createdAt
|
|
149
|
+
};
|
|
150
|
+
}
|
|
124
151
|
export function resolveScheduledStartAt(internals, options, submissionTime, callbacks) {
|
|
125
152
|
assertExclusiveStartWorkflowOptions(options?.startAt, options?.startAfter);
|
|
126
153
|
if (options?.startAt !== void 0)
|
|
@@ -138,7 +165,7 @@ export function resolveScheduledStartAt(internals, options, submissionTime, call
|
|
|
138
165
|
export function parseStartOptionDuration(_internals, duration, fieldName, _callbacks) {
|
|
139
166
|
return parseStartWorkflowDuration(duration, fieldName);
|
|
140
167
|
}
|
|
141
|
-
function buildInitialIdentitySlice(workflowId, type, input, versionTuple, executionStateOwnerId, delayedStartTimer, now, tags) {
|
|
168
|
+
function buildInitialIdentitySlice(workflowId, type, input, versionTuple, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken, delayedStartTimer, now, tags) {
|
|
142
169
|
return {
|
|
143
170
|
id: workflowId,
|
|
144
171
|
type,
|
|
@@ -147,6 +174,8 @@ function buildInitialIdentitySlice(workflowId, type, input, versionTuple, execut
|
|
|
147
174
|
versionTuple,
|
|
148
175
|
workflowExecutionToken: crypto.randomUUID(),
|
|
149
176
|
...executionStateOwnerId !== void 0 && { executionStateOwnerId },
|
|
177
|
+
...parentWorkflowId !== void 0 && { parentWorkflowId },
|
|
178
|
+
...parentWorkflowExecutionToken !== void 0 && { parentWorkflowExecutionToken },
|
|
150
179
|
createdAt: now,
|
|
151
180
|
...!delayedStartTimer && { startedAt: now },
|
|
152
181
|
updatedAt: now,
|
|
@@ -163,8 +192,8 @@ function resolveInitialExecutionDeadline(internals, options, delayedStartTimer,
|
|
|
163
192
|
throw new StartWorkflowValidationError("options.executionTimeout must resolve to a finite, non-negative deadline");
|
|
164
193
|
}
|
|
165
194
|
}
|
|
166
|
-
export function createInitialWorkflowState(internals, workflowId, type, input, versionTuple, options, tags, executionStateOwnerId, delayedStartTimer, callbacks) {
|
|
167
|
-
const now = internals.options.getNow(), state = buildInitialIdentitySlice(workflowId, type, input, versionTuple, executionStateOwnerId, delayedStartTimer, now, tags), executionDeadline = resolveInitialExecutionDeadline(internals, options, delayedStartTimer, now, callbacks);
|
|
195
|
+
export function createInitialWorkflowState(internals, workflowId, type, input, versionTuple, options, tags, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken, delayedStartTimer, callbacks) {
|
|
196
|
+
const now = internals.options.getNow(), state = buildInitialIdentitySlice(workflowId, type, input, versionTuple, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken, delayedStartTimer, now, tags), executionDeadline = resolveInitialExecutionDeadline(internals, options, delayedStartTimer, now, callbacks);
|
|
168
197
|
if (executionDeadline !== void 0)
|
|
169
198
|
state.executionDeadline = executionDeadline;
|
|
170
199
|
return state;
|
|
@@ -4,6 +4,7 @@ import { RegExpExtensionDecodeError } from "../../codec/extension-codec.js";
|
|
|
4
4
|
import { Context, setContextWorkflowInterceptor } from "../../context.js";
|
|
5
5
|
import { EMPTY_EVENT_HEAD } from "../../event-log.js";
|
|
6
6
|
import { WorkflowRecoverySkippedEvent, WorkflowStartedEvent } from "../../events.js";
|
|
7
|
+
import { VersionMismatchError } from "../../versioning.js";
|
|
7
8
|
import { createCancelHandlerRegistration, resetCancelHandlers } from "../cancel-handlers.js";
|
|
8
9
|
import { forgetCommittedCheckpointBytes } from "../checkpoint-commit-snapshots.js";
|
|
9
10
|
import { hydrateCheckpointReplayState } from "../checkpoint-replay.js";
|
|
@@ -60,6 +61,21 @@ async function preflightRecoverAll(internals, callbacks) {
|
|
|
60
61
|
}
|
|
61
62
|
return result;
|
|
62
63
|
}
|
|
64
|
+
async function recoverEntryOrIsolateFailure(internals, workflowId, callbacks, options) {
|
|
65
|
+
try {
|
|
66
|
+
return await resume(internals, workflowId, callbacks, options?.onRecoveredWorkflow);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error instanceof RegExpExtensionDecodeError) {
|
|
69
|
+
await callbacks.failWorkflowForCheckpointDecodeError(workflowId, error);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (error instanceof VersionMismatchError && options?.versionMismatchPolicy !== "throw") {
|
|
73
|
+
await callbacks.failWorkflowForVersionMismatch(workflowId, error);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
63
79
|
export async function recoverAll(internals, callbacks, options) {
|
|
64
80
|
const preflight = await preflightRecoverAll(internals, callbacks), handles = [];
|
|
65
81
|
if (preflight.missingWorkflows.length > 0 && options?.acknowledgeUnknownWorkflowTypes !== !0)
|
|
@@ -76,15 +92,9 @@ export async function recoverAll(internals, callbacks, options) {
|
|
|
76
92
|
callbacks.dispatchEvent(new WorkflowRecoverySkippedEvent(entry.workflow.workflowId, entry.workflow.type, "type-not-registered"));
|
|
77
93
|
continue;
|
|
78
94
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (error instanceof RegExpExtensionDecodeError) {
|
|
83
|
-
await callbacks.failWorkflowForCheckpointDecodeError(entry.workflowId, error);
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
throw error;
|
|
87
|
-
}
|
|
95
|
+
const handle = await recoverEntryOrIsolateFailure(internals, entry.workflowId, callbacks, options);
|
|
96
|
+
if (handle !== null)
|
|
97
|
+
handles.push(handle);
|
|
88
98
|
}
|
|
89
99
|
return handles;
|
|
90
100
|
}
|
|
@@ -36,18 +36,7 @@ export declare function processParallelOperation(internals: EngineInternals, wor
|
|
|
36
36
|
export declare function processRaceOperation(internals: EngineInternals, workflowId: string, operation: RaceOperation, callbacks: Pick<CoordinationOperationCallbacks, 'executeSubOperation' | 'runOperationWithResult'>): Promise<void>;
|
|
37
37
|
export declare function assertValidRaceBranchNames(operation: RaceOperation): void;
|
|
38
38
|
export declare function wrapRaceWinner(operation: RaceOperation, winnerIndex: number, value: unknown): unknown;
|
|
39
|
-
|
|
40
|
-
* Execute race branches while giving an already-buffered signal priority over a
|
|
41
|
-
* literal zero-duration sleep. The preflight is non-destructive: the selected
|
|
42
|
-
* wait-signal branch still returns its deferred-consume envelope, so the owning
|
|
43
|
-
* coordinator remains the only place that consumes the durable record.
|
|
44
|
-
*
|
|
45
|
-
* Positive-duration sleeps deliberately bypass this preflight, including when
|
|
46
|
-
* their deadline becomes past-due before dispatch. That keeps ordinary timeout
|
|
47
|
-
* races on the existing Promise.race path and limits the stronger ordering
|
|
48
|
-
* guarantee to the explicit non-blocking-drain idiom.
|
|
49
|
-
*/
|
|
50
|
-
export declare function executeRaceSubOperations(internals: EngineInternals, workflowId: string, operations: readonly ContextOperationRequest[], execute: (operation: ContextOperationRequest, signal: AbortSignal) => Promise<unknown>, parentSignal?: AbortSignal, wrapWinner?: (winnerIndex: number, value: unknown) => unknown): Promise<unknown>;
|
|
39
|
+
export declare function executeRaceSubOperations(internals: EngineInternals, workflowId: string, operations: readonly ContextOperationRequest[], execute: (operation: ContextOperationRequest, signal: AbortSignal) => Promise<unknown>, parentSignal?: AbortSignal, wrapWinner?: (winnerIndex: number, value: unknown) => unknown, observeWinner?: (winnerIndex: number, error?: unknown) => void): Promise<unknown>;
|
|
51
40
|
export declare function processRunAllOperation(internals: EngineInternals, workflowId: string, operation: RunAllOperation, callbacks: Pick<CoordinationOperationCallbacks, 'runOperationWithResult'>): Promise<void>;
|
|
52
41
|
export declare function isConfiguredInlineActivity(fn: Function): fn is RunAllOperation['branches'][string][0] & ActivityFunctionWithMetadata;
|
|
53
42
|
/**
|