@usine/engine 0.3.0 → 0.5.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/LICENSE +661 -21
- package/README.md +112 -38
- package/dist/board-moves/board-moves.d.ts +20 -0
- package/dist/board-moves/board-moves.d.ts.map +1 -0
- package/dist/board-moves/board-moves.js +74 -0
- package/dist/board-moves/board-moves.js.map +1 -0
- package/dist/board-moves/model.d.ts +21 -0
- package/dist/board-moves/model.d.ts.map +1 -0
- package/dist/board-moves/model.js +22 -0
- package/dist/board-moves/model.js.map +1 -0
- package/dist/cursor/cursor.d.ts +2 -6
- package/dist/cursor/cursor.d.ts.map +1 -1
- package/dist/cursor/cursor.js +2 -6
- package/dist/cursor/cursor.js.map +1 -1
- package/dist/cycle-budget/cycle-budget.d.ts +14 -8
- package/dist/cycle-budget/cycle-budget.d.ts.map +1 -1
- package/dist/cycle-budget/cycle-budget.js +51 -10
- package/dist/cycle-budget/cycle-budget.js.map +1 -1
- package/dist/cycle-budget/model.d.ts +6 -2
- package/dist/cycle-budget/model.d.ts.map +1 -1
- package/dist/cycle-budget/model.js +5 -2
- package/dist/cycle-budget/model.js.map +1 -1
- package/dist/cycle-budget/queries.d.ts +1 -1
- package/dist/cycle-budget/queries.d.ts.map +1 -1
- package/dist/cycle-budget/queries.js +3 -3
- package/dist/cycle-budget/queries.js.map +1 -1
- package/dist/database/database.d.ts +1 -1
- package/dist/database/database.d.ts.map +1 -1
- package/dist/database/local-sqlite.d.ts +13 -10
- package/dist/database/local-sqlite.d.ts.map +1 -1
- package/dist/database/local-sqlite.js +22 -17
- package/dist/database/local-sqlite.js.map +1 -1
- package/dist/database/schema.d.ts +668 -36
- package/dist/database/schema.d.ts.map +1 -1
- package/dist/database/schema.js +123 -23
- package/dist/database/schema.js.map +1 -1
- package/dist/{workflow → engine}/admission.d.ts +2 -2
- package/dist/engine/admission.d.ts.map +1 -0
- package/dist/{workflow → engine}/admission.js +4 -4
- package/dist/engine/admission.js.map +1 -0
- package/dist/engine/checkout-recovery.d.ts +79 -0
- package/dist/engine/checkout-recovery.d.ts.map +1 -0
- package/dist/engine/checkout-recovery.js +238 -0
- package/dist/engine/checkout-recovery.js.map +1 -0
- package/dist/engine/engine.d.ts +67 -26
- package/dist/engine/engine.d.ts.map +1 -1
- package/dist/engine/engine.js +136 -129
- package/dist/engine/engine.js.map +1 -1
- package/dist/engine/error.d.ts +29 -10
- package/dist/engine/error.d.ts.map +1 -1
- package/dist/engine/error.js +28 -8
- package/dist/engine/error.js.map +1 -1
- package/dist/engine/lifecycle.d.ts +83 -28
- package/dist/engine/lifecycle.d.ts.map +1 -1
- package/dist/engine/lifecycle.js +94 -45
- package/dist/engine/lifecycle.js.map +1 -1
- package/dist/engine/retry.d.ts +16 -0
- package/dist/engine/retry.d.ts.map +1 -0
- package/dist/engine/retry.js +18 -0
- package/dist/engine/retry.js.map +1 -0
- package/dist/engine/run-again.d.ts +45 -0
- package/dist/engine/run-again.d.ts.map +1 -0
- package/dist/engine/run-again.js +56 -0
- package/dist/engine/run-again.js.map +1 -0
- package/dist/engine/run-driver.d.ts +68 -0
- package/dist/engine/run-driver.d.ts.map +1 -0
- package/dist/engine/run-driver.js +448 -0
- package/dist/engine/run-driver.js.map +1 -0
- package/dist/engine/shutdown.d.ts +3 -4
- package/dist/engine/shutdown.d.ts.map +1 -1
- package/dist/engine/shutdown.js +3 -4
- package/dist/engine/shutdown.js.map +1 -1
- package/dist/engine/submission.d.ts +31 -11
- package/dist/engine/submission.d.ts.map +1 -1
- package/dist/engine/submission.js +43 -12
- package/dist/engine/submission.js.map +1 -1
- package/dist/engine/unconfirmed-stops.d.ts +27 -0
- package/dist/engine/unconfirmed-stops.d.ts.map +1 -0
- package/dist/engine/unconfirmed-stops.js +26 -0
- package/dist/engine/unconfirmed-stops.js.map +1 -0
- package/dist/item-projection/item-projection.d.ts +14 -4
- package/dist/item-projection/item-projection.d.ts.map +1 -1
- package/dist/item-projection/item-projection.js +60 -14
- package/dist/item-projection/item-projection.js.map +1 -1
- package/dist/item-projection/model.d.ts +5 -1
- package/dist/item-projection/model.d.ts.map +1 -1
- package/dist/item-projection/model.js +6 -2
- package/dist/item-projection/model.js.map +1 -1
- package/dist/loop-control/loop-control.d.ts +5 -5
- package/dist/loop-control/loop-control.d.ts.map +1 -1
- package/dist/loop-control/loop-control.js +4 -4
- package/dist/loop-control/loop-control.js.map +1 -1
- package/dist/loop-control/model.d.ts +1 -1
- package/dist/loop-control/model.d.ts.map +1 -1
- package/dist/loop-control/model.js +1 -1
- package/dist/loop-control/model.js.map +1 -1
- package/dist/repository-label-projection/model.d.ts +2 -2
- package/dist/repository-label-projection/model.d.ts.map +1 -1
- package/dist/repository-label-projection/model.js +2 -2
- package/dist/repository-label-projection/model.js.map +1 -1
- package/dist/repository-label-projection/repository-label-projection.d.ts +1 -1
- package/dist/repository-label-projection/repository-label-projection.d.ts.map +1 -1
- package/dist/repository-label-projection/repository-label-projection.js +1 -1
- package/dist/repository-label-projection/repository-label-projection.js.map +1 -1
- package/dist/run-reader/model.d.ts +62 -4
- package/dist/run-reader/model.d.ts.map +1 -1
- package/dist/run-reader/model.js +66 -7
- package/dist/run-reader/model.js.map +1 -1
- package/dist/run-reader/run-reader.d.ts +25 -10
- package/dist/run-reader/run-reader.d.ts.map +1 -1
- package/dist/run-reader/run-reader.js +25 -7
- package/dist/run-reader/run-reader.js.map +1 -1
- package/dist/step-executor.d.ts +86 -13
- package/dist/step-executor.d.ts.map +1 -1
- package/dist/step-executor.js +10 -2
- package/dist/step-executor.js.map +1 -1
- package/dist/store/attempt-windows.d.ts +8 -0
- package/dist/store/attempt-windows.d.ts.map +1 -0
- package/dist/store/attempt-windows.js +53 -0
- package/dist/store/attempt-windows.js.map +1 -0
- package/dist/store/codec.d.ts +242 -43
- package/dist/store/codec.d.ts.map +1 -1
- package/dist/store/codec.js +61 -16
- package/dist/store/codec.js.map +1 -1
- package/dist/store/leftovers.d.ts +10 -0
- package/dist/store/leftovers.d.ts.map +1 -0
- package/dist/store/leftovers.js +43 -0
- package/dist/store/leftovers.js.map +1 -0
- package/dist/store/loop-items.d.ts +16 -0
- package/dist/store/loop-items.d.ts.map +1 -0
- package/dist/store/loop-items.js +185 -0
- package/dist/store/loop-items.js.map +1 -0
- package/dist/store/queries.d.ts +385 -36
- package/dist/store/queries.d.ts.map +1 -1
- package/dist/store/queries.js +355 -107
- package/dist/store/queries.js.map +1 -1
- package/dist/store/store.d.ts +106 -54
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +497 -190
- package/dist/store/store.js.map +1 -1
- package/dist/store/transcript.d.ts +3 -3
- package/dist/store/transcript.d.ts.map +1 -1
- package/dist/store/transcript.js +25 -6
- package/dist/store/transcript.js.map +1 -1
- package/dist/transcript.d.ts +19 -20
- package/dist/transcript.d.ts.map +1 -1
- package/dist/transcript.js +23 -21
- package/dist/transcript.js.map +1 -1
- package/dist/trigger-condition.d.ts +23 -0
- package/dist/trigger-condition.d.ts.map +1 -0
- package/dist/trigger-condition.js +8 -0
- package/dist/trigger-condition.js.map +1 -0
- package/drizzle/20260917071139_resolve_run_failure/migration.sql +1 -0
- package/drizzle/20260917071139_resolve_run_failure/snapshot.json +1471 -0
- package/drizzle/20260918032643_attempt_salvage/migration.sql +1 -0
- package/drizzle/20260918032643_attempt_salvage/snapshot.json +1481 -0
- package/drizzle/20261011153856_drop_workflow_tables/migration.sql +4 -0
- package/drizzle/20261011153856_drop_workflow_tables/snapshot.json +1433 -0
- package/drizzle/20261017155043_attempt_salvage_check/migration.sql +41 -0
- package/drizzle/20261017155043_attempt_salvage_check/snapshot.json +1421 -0
- package/drizzle/20261018162700_discard_attempt_leftovers/migration.sql +1 -0
- package/drizzle/20261018162700_discard_attempt_leftovers/snapshot.json +1431 -0
- package/drizzle/20261018172605_loop_items_and_reopenings/migration.sql +15 -0
- package/drizzle/20261018172605_loop_items_and_reopenings/snapshot.json +1574 -0
- package/drizzle/20261018180339_attempt_ended_at/migration.sql +1 -0
- package/drizzle/20261018180339_attempt_ended_at/snapshot.json +1584 -0
- package/drizzle/20261019104043_run_approval_source/migration.sql +15 -0
- package/drizzle/20261019104043_run_approval_source/snapshot.json +1610 -0
- package/drizzle/20261019133538_board_moves/migration.sql +14 -0
- package/drizzle/20261019133538_board_moves/snapshot.json +1731 -0
- package/drizzle/20261019170538_item_projection_gone/migration.sql +1 -0
- package/drizzle/20261019170538_item_projection_gone/snapshot.json +1741 -0
- package/drizzle/20261019180649_run_again_events/migration.sql +7 -0
- package/drizzle/20261019180649_run_again_events/snapshot.json +1804 -0
- package/drizzle/20261019185008_trigger_event_permissions/migration.sql +1 -0
- package/drizzle/20261019185008_trigger_event_permissions/snapshot.json +1814 -0
- package/drizzle/20261020103746_attempt_start/migration.sql +5 -0
- package/drizzle/20261020103746_attempt_start/snapshot.json +1844 -0
- package/drizzle/20261020125211_attempt_comments/migration.sql +1 -0
- package/drizzle/20261020125211_attempt_comments/snapshot.json +1854 -0
- package/drizzle/20261020191320_run_closed_at/migration.sql +6 -0
- package/drizzle/20261020191320_run_closed_at/snapshot.json +1864 -0
- package/drizzle/20261023091428_rename_loop_item_hold_to_suppression/migration.sql +2 -0
- package/drizzle/20261023091428_rename_loop_item_hold_to_suppression/snapshot.json +1867 -0
- package/drizzle/20261024162954_cycle_ask_closures/migration.sql +10 -0
- package/drizzle/20261024162954_cycle_ask_closures/snapshot.json +1948 -0
- package/drizzle/20261027104206_attempt_out_of_memory/migration.sql +1 -0
- package/drizzle/20261027104206_attempt_out_of_memory/snapshot.json +1958 -0
- package/drizzle/20261027191944_failure_resolution/migration.sql +1 -0
- package/drizzle/20261027191944_failure_resolution/snapshot.json +1968 -0
- package/package.json +22 -12
- package/dist/workflow/admission.d.ts.map +0 -1
- package/dist/workflow/admission.js.map +0 -1
- package/dist/workflow/command.d.ts +0 -13
- package/dist/workflow/command.d.ts.map +0 -1
- package/dist/workflow/command.js +0 -17
- package/dist/workflow/command.js.map +0 -1
- package/dist/workflow/workflow.d.ts +0 -18
- package/dist/workflow/workflow.d.ts.map +0 -1
- package/dist/workflow/workflow.js +0 -108
- package/dist/workflow/workflow.js.map +0 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { AttemptId } from "@usine/core/attempt";
|
|
2
|
+
import { WorkerName } from "@usine/core/worker";
|
|
3
|
+
import { Array as EffectArray, Effect, Option, Ref, Result, Schema } from "effect";
|
|
4
|
+
/**
|
|
5
|
+
* An error for an Attempt whose parent task couldn't be confirmed stopped. Its slot of `worker`,
|
|
6
|
+
* and any checkout startup kept, stay kept, and the Run's next Attempt doesn't start.
|
|
7
|
+
*/
|
|
8
|
+
class ParentStopUnconfirmedError extends Schema.TaggedError("@usine/engine/internal/ParentStopUnconfirmedError")("ParentStopUnconfirmedError", {
|
|
9
|
+
attemptId: AttemptId,
|
|
10
|
+
worker: WorkerName,
|
|
11
|
+
cause: Schema.Defect(),
|
|
12
|
+
}) {
|
|
13
|
+
}
|
|
14
|
+
/** Returns `map` without `key`. */
|
|
15
|
+
export const without = (map, key) => {
|
|
16
|
+
const remaining = new Map(map);
|
|
17
|
+
remaining.delete(key);
|
|
18
|
+
return remaining;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Creates the checkout recovery steps that `RunDriver` uses at startup, on reattach, and on cancel.
|
|
22
|
+
*
|
|
23
|
+
* `atStartup` reconciles the checkouts left on Workers through `StepExecutor.recover`. It keeps
|
|
24
|
+
* the checkout, and occupies a Worker slot through `StepExecutor.occupy` (#177), for an open
|
|
25
|
+
* Attempt whose parent task is live or unreadable and for a closed Attempt whose parent task
|
|
26
|
+
* isn't confirmed stopped. `acquired` hands a kept checkout and slot to the reattaching
|
|
27
|
+
* execution. `hold` keeps the slot of an Attempt whose parent task may still run after a cancel
|
|
28
|
+
* or a failure (#475, #512). `reconcile` reconciles a kept checkout that the Run closes without
|
|
29
|
+
* that hand-off (#180), and releases the slot once the parent task is confirmed stopped.
|
|
30
|
+
*/
|
|
31
|
+
export const checkoutRecoveryFor = Effect.fn("CheckoutRecovery.for")(function* (store, executor) {
|
|
32
|
+
// The slots of Attempts whose parent task may still run, by Attempt.
|
|
33
|
+
const kept = yield* Ref.make(new Map());
|
|
34
|
+
/** Reconciles `attempt`'s checkout. On failure, logs an error and leaves the checkout on its Worker. */
|
|
35
|
+
const recover = (attempt) => executor
|
|
36
|
+
.recover(attempt, {
|
|
37
|
+
salvage: (salvage) => store.recordSalvage(attempt.attemptId, salvage),
|
|
38
|
+
comments: (comments) => store.recordComments(attempt.attemptId, comments),
|
|
39
|
+
windows: store.attemptWindows(attempt.attemptId),
|
|
40
|
+
})
|
|
41
|
+
.pipe(Effect.tapError((error) => Effect.logError("Attempt salvage reconciliation failed; work retained", {
|
|
42
|
+
attemptId: attempt.attemptId,
|
|
43
|
+
worker: attempt.worker,
|
|
44
|
+
message: String(error),
|
|
45
|
+
})), Effect.ignore);
|
|
46
|
+
/**
|
|
47
|
+
* Keeps `attempt`'s checkout and occupies a slot on its Worker, recording the lease in the same
|
|
48
|
+
* uninterruptible step.
|
|
49
|
+
*/
|
|
50
|
+
const keep = Effect.fn("CheckoutRecovery.keep")(function* (attempt) {
|
|
51
|
+
yield* executor.occupy(attempt.worker, attempt.attemptId).pipe(Effect.flatMap((lease) => Effect.cached(lease.release).pipe(Effect.map((release) => ({
|
|
52
|
+
worker: lease.worker,
|
|
53
|
+
release,
|
|
54
|
+
checkoutKept: true,
|
|
55
|
+
})))), Effect.flatMap((occupied) => Ref.update(kept, (leases) => new Map(leases).set(attempt.attemptId, occupied))), Effect.uninterruptible);
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Keeps the checkout and a slot for an open Attempt whose parent task is live or whose liveness
|
|
59
|
+
* can't be read. Otherwise reconciles the checkout.
|
|
60
|
+
*/
|
|
61
|
+
const recoverOpen = Effect.fn("CheckoutRecovery.recoverOpen")(function* (attempt) {
|
|
62
|
+
const fields = { attemptId: attempt.attemptId, worker: attempt.worker };
|
|
63
|
+
yield* Effect.annotateCurrentSpan(fields);
|
|
64
|
+
const live = yield* executor.isLive(attempt.attemptId).pipe(Effect.result);
|
|
65
|
+
if (Result.isSuccess(live) && !live.success)
|
|
66
|
+
return yield* recover(attempt);
|
|
67
|
+
if (Result.isFailure(live))
|
|
68
|
+
yield* Effect.logWarning("Could not read whether an open Attempt's parent task is live; its checkout stays for its Run to decide", { ...fields, errorTag: live.failure._tag, message: live.failure.message });
|
|
69
|
+
else
|
|
70
|
+
yield* Effect.logInfo("Leaving the checkout of an open Attempt whose parent task is live for its Run to reattach", fields);
|
|
71
|
+
yield* keep(attempt);
|
|
72
|
+
yield* Effect.logInfo("Occupied a slot on the Worker of an open Attempt kept for its Run to reattach", fields);
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Reconciles a closed Attempt's checkout if its parent task is confirmed stopped. Otherwise
|
|
76
|
+
* keeps the checkout and a slot, and returns the Attempt (#177).
|
|
77
|
+
*/
|
|
78
|
+
const recoverClosed = Effect.fn("CheckoutRecovery.recoverClosed")(function* (attempt) {
|
|
79
|
+
const fields = { attemptId: attempt.attemptId, runId: attempt.runId, worker: attempt.worker };
|
|
80
|
+
yield* Effect.annotateCurrentSpan(fields);
|
|
81
|
+
// `recover` also stops the task, but its failure doesn't distinguish an unconfirmed stop from
|
|
82
|
+
// a failed salvage.
|
|
83
|
+
const stopped = yield* executor.interrupt(attempt.attemptId, "startup").pipe(Effect.result);
|
|
84
|
+
if (Result.isSuccess(stopped)) {
|
|
85
|
+
yield* recover(attempt);
|
|
86
|
+
return Option.none();
|
|
87
|
+
}
|
|
88
|
+
yield* Effect.logWarning("Could not confirm that the parent task of a closed Attempt stopped; its checkout and a slot of its Worker stay kept, and no Attempt starts on its Loop's Item, until a reconcile confirms the stop", { ...fields, errorTag: stopped.failure._tag, message: stopped.failure.message });
|
|
89
|
+
yield* keep(attempt);
|
|
90
|
+
return Option.some(attempt);
|
|
91
|
+
});
|
|
92
|
+
/**
|
|
93
|
+
* Reconciles every persisted Attempt on a configured Worker. Returns the closed Attempts whose
|
|
94
|
+
* parent task isn't confirmed stopped.
|
|
95
|
+
*/
|
|
96
|
+
const atStartup = Effect.fn("CheckoutRecovery.atStartup")(function* () {
|
|
97
|
+
const configured = new Set(yield* executor.workers);
|
|
98
|
+
const candidates = yield* store.salvageCandidates;
|
|
99
|
+
const reconcilable = candidates.filter(({ worker }) => configured.has(worker));
|
|
100
|
+
const unconfigured = candidates.filter(({ worker }) => !configured.has(worker));
|
|
101
|
+
if (unconfigured.length > 0) {
|
|
102
|
+
yield* Effect.logWarning("Attempts recorded on Workers that are not configured were not reconciled; their checkouts stay until those Workers are configured again or their leftovers are discarded", {
|
|
103
|
+
attempts: unconfigured.length,
|
|
104
|
+
workers: [...new Set(unconfigured.map(({ worker }) => worker))].sort().join(","),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// Runs before Run recovery, so a retry starts only after the previous Attempt's work is
|
|
108
|
+
// recorded. A failed recovery leaves the checkout on disk.
|
|
109
|
+
const unstopped = yield* Effect.forEach(reconcilable, (attempt) => attempt.open
|
|
110
|
+
? recoverOpen(attempt).pipe(Effect.as(Option.none()))
|
|
111
|
+
: recoverClosed(attempt));
|
|
112
|
+
return EffectArray.getSomes(unstopped);
|
|
113
|
+
});
|
|
114
|
+
/**
|
|
115
|
+
* Returns the slot that startup occupied with the checkout it kept for `attemptId`, or `None`.
|
|
116
|
+
* Until the execution acquires the checkout, the slot's `release` does nothing; `reconcile`
|
|
117
|
+
* frees it.
|
|
118
|
+
*/
|
|
119
|
+
const reattachSlot = Effect.fn("CheckoutRecovery.reattachSlot")(function* (attemptId) {
|
|
120
|
+
const occupied = Option.filter(Option.fromUndefinedOr((yield* Ref.get(kept)).get(attemptId)), ({ checkoutKept }) => checkoutKept);
|
|
121
|
+
return Option.map(occupied, (entry) => ({
|
|
122
|
+
worker: entry.worker,
|
|
123
|
+
release: Ref.get(kept).pipe(Effect.flatMap((leases) => leases.get(attemptId) === entry
|
|
124
|
+
? Effect.logInfo("The slot startup occupied stays kept with the checkout no execution acquired, until the Attempt's parent task is confirmed stopped", { attemptId, worker: entry.worker })
|
|
125
|
+
: entry.release)),
|
|
126
|
+
}));
|
|
127
|
+
});
|
|
128
|
+
/**
|
|
129
|
+
* Hands the kept checkout of `attemptId` to its execution; the Run then releases the slot when
|
|
130
|
+
* the Attempt ends. Does nothing for other Attempts.
|
|
131
|
+
*/
|
|
132
|
+
const acquired = Effect.fn("CheckoutRecovery.acquired")(function* (attemptId) {
|
|
133
|
+
const handedOver = yield* Ref.modify(kept, (leases) => leases.get(attemptId)?.checkoutKept === true
|
|
134
|
+
? [true, without(leases, attemptId)]
|
|
135
|
+
: [false, leases]);
|
|
136
|
+
if (handedOver)
|
|
137
|
+
yield* Effect.logInfo("The reattached Attempt's execution acquired the checkout startup kept; its executor releases the checkout from here, and its Run the slot once the Attempt ends", { attemptId });
|
|
138
|
+
});
|
|
139
|
+
/**
|
|
140
|
+
* Keeps `lease` as the slot of `attemptId`, an Attempt whose parent task may still run, until
|
|
141
|
+
* `reconcile` confirms that the task stopped. If the Attempt already has a slot here, releases
|
|
142
|
+
* `lease` instead.
|
|
143
|
+
*/
|
|
144
|
+
const hold = Effect.fn("CheckoutRecovery.hold")(function* (attemptId, lease) {
|
|
145
|
+
const fields = { attemptId, worker: lease.worker };
|
|
146
|
+
yield* Effect.annotateCurrentSpan(fields);
|
|
147
|
+
const release = yield* Effect.cached(lease.release);
|
|
148
|
+
const held = yield* Ref.modify(kept, (leases) => leases.has(attemptId)
|
|
149
|
+
? [false, leases]
|
|
150
|
+
: [
|
|
151
|
+
true,
|
|
152
|
+
new Map(leases).set(attemptId, {
|
|
153
|
+
worker: lease.worker,
|
|
154
|
+
release,
|
|
155
|
+
checkoutKept: false,
|
|
156
|
+
}),
|
|
157
|
+
]);
|
|
158
|
+
if (held) {
|
|
159
|
+
yield* Effect.logInfo("The Attempt keeps its Run's slot until its parent task is confirmed stopped", fields);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
yield* Effect.logDebug("The Attempt already has a slot kept until its parent task is confirmed stopped; releasing its Run's lease", fields);
|
|
163
|
+
yield* release;
|
|
164
|
+
}, Effect.uninterruptible);
|
|
165
|
+
/**
|
|
166
|
+
* Stops the parent task of `attemptId` for `reason`. Fails with `ParentStopUnconfirmedError` if
|
|
167
|
+
* the stop isn't confirmed.
|
|
168
|
+
*/
|
|
169
|
+
const confirmStop = Effect.fn("CheckoutRecovery.confirmStop")(function* (attemptId, occupied, reason) {
|
|
170
|
+
const fields = {
|
|
171
|
+
attemptId,
|
|
172
|
+
worker: occupied.worker,
|
|
173
|
+
checkoutKept: occupied.checkoutKept,
|
|
174
|
+
reason,
|
|
175
|
+
};
|
|
176
|
+
yield* Effect.annotateCurrentSpan(fields);
|
|
177
|
+
const stopped = yield* executor.interrupt(attemptId, reason).pipe(Effect.result);
|
|
178
|
+
if (Result.isSuccess(stopped))
|
|
179
|
+
return;
|
|
180
|
+
const failure = { ...fields, errorTag: stopped.failure._tag, message: stopped.failure.message };
|
|
181
|
+
yield* occupied.checkoutKept
|
|
182
|
+
? Effect.logWarning("Could not confirm that the parent task of an Attempt its Run does not reattach stopped; its checkout and its Worker's slot stay, and the Run starts no next Attempt until the stop is confirmed", failure)
|
|
183
|
+
: Effect.logWarning("Could not confirm that the parent task of a closed Attempt stopped; its Worker's slot stays taken, and no Attempt starts on its Loop's Item, until a reconcile confirms the stop", failure);
|
|
184
|
+
return yield* new ParentStopUnconfirmedError({
|
|
185
|
+
attemptId,
|
|
186
|
+
worker: occupied.worker,
|
|
187
|
+
cause: stopped.failure,
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
/** Reconciles the checkout startup kept for `attemptId`, whose parent task is confirmed stopped. */
|
|
191
|
+
const recoverKept = Effect.fn("CheckoutRecovery.recoverKept")(function* (attemptId) {
|
|
192
|
+
const found = yield* store.salvageCandidate(attemptId).pipe(Effect.result);
|
|
193
|
+
if (Result.isFailure(found)) {
|
|
194
|
+
yield* Effect.logError("Could not read the Attempt whose checkout startup kept; the checkout stays until the next startup", { attemptId, errorTag: found.failure._tag });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (Option.isNone(found.success)) {
|
|
198
|
+
yield* Effect.logWarning("The leftovers of the Attempt whose checkout startup kept were discarded; the checkout stays", { attemptId });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const attempt = found.success.value;
|
|
202
|
+
const fields = { attemptId, worker: attempt.worker, open: attempt.open };
|
|
203
|
+
yield* Effect.annotateCurrentSpan(fields);
|
|
204
|
+
if (!(yield* executor.workers).includes(attempt.worker)) {
|
|
205
|
+
yield* Effect.logWarning("The Worker of the Attempt whose checkout startup kept is no longer configured; the checkout stays until it is configured again or its leftovers are discarded", fields);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
// The Run doesn't reattach the Attempt, so reconcile even if `isLive` still reports it, as for
|
|
209
|
+
// an unharvested parent report.
|
|
210
|
+
yield* Effect.logInfo("Reconciling the checkout startup kept for an Attempt that was not reattached", fields);
|
|
211
|
+
yield* recover(attempt);
|
|
212
|
+
});
|
|
213
|
+
/**
|
|
214
|
+
* Stops the parent task of `attemptId` for `reason` if a slot is kept for it, then reconciles a
|
|
215
|
+
* checkout startup kept and releases the slot. Fails with `ParentStopUnconfirmedError` and keeps
|
|
216
|
+
* both if the stop isn't confirmed.
|
|
217
|
+
*/
|
|
218
|
+
const reconcile = Effect.fn("CheckoutRecovery.reconcile")(function* (attemptId, reason) {
|
|
219
|
+
yield* Effect.annotateCurrentSpan({ attemptId, reason });
|
|
220
|
+
const occupied = (yield* Ref.get(kept)).get(attemptId);
|
|
221
|
+
if (occupied === undefined) {
|
|
222
|
+
yield* Effect.logDebug("No slot kept for the Attempt awaits its parent task's stop", {
|
|
223
|
+
attemptId,
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
// The parent task must stop before the reconcile, the next Attempt, or the slot's release.
|
|
228
|
+
yield* confirmStop(attemptId, occupied, reason);
|
|
229
|
+
if (occupied.checkoutKept)
|
|
230
|
+
yield* recoverKept(attemptId);
|
|
231
|
+
// Removed only after reconciling, so a cancel during the reconcile reconciles again and the
|
|
232
|
+
// slot stays taken while the parent task can still run (#177).
|
|
233
|
+
yield* Ref.update(kept, (leases) => without(leases, attemptId)).pipe(Effect.andThen(occupied.release), Effect.uninterruptible);
|
|
234
|
+
yield* Effect.logInfo("Released the slot kept for an Attempt whose parent task is confirmed stopped", { attemptId, worker: occupied.worker, checkoutKept: occupied.checkoutKept });
|
|
235
|
+
});
|
|
236
|
+
return { atStartup, reattachSlot, acquired, hold, reconcile };
|
|
237
|
+
});
|
|
238
|
+
//# sourceMappingURL=checkout-recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout-recovery.js","sourceRoot":"","sources":["../../src/engine/checkout-recovery.ts"],"names":[],"mappings":"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"}
|
package/dist/engine/engine.d.ts
CHANGED
|
@@ -1,59 +1,100 @@
|
|
|
1
1
|
import { Event } from "@usine/core/event";
|
|
2
|
-
import {
|
|
2
|
+
import { AttemptId } from "@usine/core/attempt";
|
|
3
3
|
import { Intervention } from "@usine/core/attempt/channel";
|
|
4
4
|
import { ItemKey } from "@usine/core/item";
|
|
5
5
|
import { LoopName } from "@usine/core/loop";
|
|
6
|
+
import type { OperatorLogin } from "@usine/core/operator";
|
|
6
7
|
import { RunId } from "@usine/core/run";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import { ApprovalSource } from "@usine/core/run/approval";
|
|
9
|
+
import type { WorkerName } from "@usine/core/worker";
|
|
10
|
+
import { Context, Crypto, type Duration, Effect, Layer, Option } from "effect";
|
|
9
11
|
import { RunDatabase } from "../database/database.ts";
|
|
10
|
-
import { type RunEngineError } from "./error.ts";
|
|
12
|
+
import { LeftoversDiscardRejectedError, type RunEngineError } from "./error.ts";
|
|
11
13
|
import type { RunSnapshot } from "../run-reader/model.ts";
|
|
12
|
-
import type
|
|
14
|
+
import { type Submission, type SubmissionResult } from "./submission.ts";
|
|
15
|
+
import type { RunAgainRequest, RunAgainResult } from "./run-again.ts";
|
|
16
|
+
import { type RetryRequest } from "./retry.ts";
|
|
13
17
|
import type { TranscriptEntry, TranscriptQuery } from "../transcript.ts";
|
|
14
18
|
import { RunReader } from "../run-reader/run-reader.ts";
|
|
15
19
|
import { ItemProjectionReader, ItemProjectionWriter } from "../item-projection/item-projection.ts";
|
|
16
20
|
import { RepositoryLabelProjectionReader, RepositoryLabelProjectionWriter } from "../repository-label-projection/repository-label-projection.ts";
|
|
17
21
|
import { StepExecutor } from "../step-executor.ts";
|
|
22
|
+
import { TriggerCondition } from "../trigger-condition.ts";
|
|
18
23
|
import { CursorStore } from "../cursor/cursor.ts";
|
|
19
24
|
import { LoopControl } from "../loop-control/loop-control.ts";
|
|
20
25
|
import { CycleBudgets } from "../cycle-budget/cycle-budget.ts";
|
|
26
|
+
import { BoardMoves } from "../board-moves/board-moves.ts";
|
|
27
|
+
import { UnconfirmedStops } from "./unconfirmed-stops.ts";
|
|
28
|
+
/** The interval between periodic reconciles, which restart open Runs whose fiber stopped. */
|
|
29
|
+
export declare const ReconcileInterval: Context.Reference<Duration.Input>;
|
|
21
30
|
declare const RunEngine_base: Context.ServiceClass<RunEngine, "@usine/engine/RunEngine", {
|
|
22
|
-
/** Stops admitting Attempts, including retries, and waits for admitted
|
|
31
|
+
/** Stops admitting Attempts, including retries, and waits for admitted Attempts to finish. Admission stays closed until restart. */
|
|
23
32
|
readonly drain: () => Effect.Effect<void>;
|
|
24
|
-
/** Records the
|
|
25
|
-
readonly approve: (runId: RunId, approval: Event) => Effect.Effect<void, RunEngineError>;
|
|
26
|
-
/**
|
|
33
|
+
/** Records the approval Event and its source, and opens the Run's approval gate. A repeated approval keeps the first source. */
|
|
34
|
+
readonly approve: (runId: RunId, approval: Event, source: ApprovalSource) => Effect.Effect<void, RunEngineError>;
|
|
35
|
+
/**
|
|
36
|
+
* Cancels an open Run and interrupts its active Attempt; does nothing for a closed Run. If the
|
|
37
|
+
* Attempt's parent task can't be confirmed stopped, fails with `AttemptCancellationError`, and
|
|
38
|
+
* until a reconcile confirms the stop, the Attempt keeps its Worker slot (#475) and no Run of
|
|
39
|
+
* the Loop on the Item starts an Attempt (#523).
|
|
40
|
+
*/
|
|
27
41
|
readonly cancel: (runId: RunId) => Effect.Effect<void, RunEngineError>;
|
|
28
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Stops reconciling the Attempts recorded on `worker`, then removes with
|
|
44
|
+
* `StepExecutor.discard` what they left outside their checkouts, and returns the number of
|
|
45
|
+
* Attempts marked. Leaves their checkouts in place. Fails with
|
|
46
|
+
* `LeftoversDiscardRejectedError` if `worker` is in `StepExecutor.workers`.
|
|
47
|
+
*/
|
|
48
|
+
readonly discardLeftovers: (worker: WorkerName) => Effect.Effect<number, RunEngineError | LeftoversDiscardRejectedError>;
|
|
49
|
+
/** Returns the Run's state, effective task and Agent, Step result, and Attempt history. */
|
|
29
50
|
readonly inspect: (runId: RunId) => Effect.Effect<RunSnapshot, RunEngineError>;
|
|
30
|
-
/**
|
|
51
|
+
/** Sends operator input to `attemptId`. Fails with `RunInterventionRejectedError` if it isn't the Run's running Attempt. */
|
|
31
52
|
readonly intervene: (runId: RunId, attemptId: AttemptId, intervention: Intervention) => Effect.Effect<void, RunEngineError>;
|
|
32
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Starts a fiber for every open Run without one, except Runs waiting for approval, and opens the
|
|
55
|
+
* queued Events that no closed Run continued, and retries the parent task stops that a cancel,
|
|
56
|
+
* a failed Attempt, or startup couldn't confirm. A Run whose Loop and Item have an unconfirmed
|
|
57
|
+
* stop starts no Attempt until a reconcile confirms it. Runs at startup and every
|
|
58
|
+
* `ReconcileInterval`.
|
|
59
|
+
*/
|
|
33
60
|
readonly reconcile: () => Effect.Effect<void, RunEngineError>;
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Marks the current failed Attempt as resolved without changing its outcome. If the Attempt
|
|
63
|
+
* stopped with a question or blocker, the Loop evaluates the Item's queued Events again.
|
|
64
|
+
*/
|
|
65
|
+
readonly resolveFailure: (runId: RunId, attemptId: AttemptId, operator: Option.Option<OperatorLogin>) => Effect.Effect<void, RunEngineError>;
|
|
66
|
+
/**
|
|
67
|
+
* Requests another Attempt for a failed Run with its existing Event, applying the request's
|
|
68
|
+
* task and Agent if set. The Attempt records the request as its start reason.
|
|
69
|
+
*/
|
|
70
|
+
readonly retry: (runId: RunId, request?: RetryRequest) => Effect.Effect<void, RunEngineError>;
|
|
71
|
+
/**
|
|
72
|
+
* Opens a new Run for the Item state of a succeeded or canceled Run, with the request's task
|
|
73
|
+
* and Agent, as an operator Event. The Item's cycle budget and the Loop's approval gate apply.
|
|
74
|
+
*/
|
|
75
|
+
readonly runAgain: (runId: RunId, request: RunAgainRequest) => Effect.Effect<RunAgainResult, RunEngineError>;
|
|
76
|
+
/** Cancels unstarted Runs and discards queued Events for a Loop's Item that stopped matching; running Attempts continue. */
|
|
37
77
|
readonly revoke: (loop: LoopName, itemKey: ItemKey) => Effect.Effect<ReadonlyArray<RunId>, RunEngineError>;
|
|
38
78
|
/**
|
|
39
|
-
* Records a matching Event and claims its Run, or queues it behind the Item's
|
|
40
|
-
*
|
|
79
|
+
* Records a matching Event and claims its Run, or queues it behind the Item's running Attempt.
|
|
80
|
+
* Deduplicates repeated Events.
|
|
41
81
|
*/
|
|
42
82
|
readonly submit: (submission: Submission) => Effect.Effect<SubmissionResult, RunEngineError>;
|
|
43
|
-
/**
|
|
83
|
+
/** Returns the requested part of an Attempt's transcript, in append order. */
|
|
44
84
|
readonly transcript: (query: TranscriptQuery) => Effect.Effect<ReadonlyArray<TranscriptEntry>, RunEngineError>;
|
|
45
85
|
}>;
|
|
46
|
-
/**
|
|
86
|
+
/** The service that records Events and drives their Runs through approval, execution, retry, and cancellation. */
|
|
47
87
|
export declare class RunEngine extends RunEngine_base {
|
|
48
88
|
}
|
|
49
89
|
/**
|
|
50
|
-
*
|
|
51
|
-
* `
|
|
52
|
-
* so Run records and pending execution remain together across restarts.
|
|
53
|
-
* The deployment supplies `Crypto` and the Worker implementation through `StepExecutor`.
|
|
90
|
+
* Returns the engine layers on `database`, which stores all durable Run state. Requires `Crypto`
|
|
91
|
+
* for Run IDs, `StepExecutor` for Workers, and `TriggerCondition` to re-check queued Events.
|
|
54
92
|
*/
|
|
55
|
-
export declare const layerWithDatabase: <DatabaseError, DatabaseRequirements>(database: Layer.Layer<RunDatabase
|
|
56
|
-
export { Submission, Claimed, Queued, Ignored, CycleBlocked, IgnoreReason, SubmissionResult, } from "./submission.ts";
|
|
93
|
+
export declare const layerWithDatabase: <DatabaseError, DatabaseRequirements>(database: Layer.Layer<RunDatabase, DatabaseError, DatabaseRequirements>) => Layer.Layer<BoardMoves | CursorStore | CycleBudgets | ItemProjectionReader | ItemProjectionWriter | LoopControl | RepositoryLabelProjectionReader | RepositoryLabelProjectionWriter | RunEngine | RunReader | UnconfirmedStops, RunEngineError | DatabaseError, Crypto.Crypto | StepExecutor | TriggerCondition | DatabaseRequirements>;
|
|
94
|
+
export { Submission, Claimed, Queued, Suppressed, Ignored, CycleBlocked, IgnoreReason, SubmissionResult, } from "./submission.ts";
|
|
95
|
+
export { RunAgainRequest, RunAgainResult } from "./run-again.ts";
|
|
96
|
+
export { RetryRequest } from "./retry.ts";
|
|
57
97
|
export { RunEngineShutdown } from "./shutdown.ts";
|
|
58
|
-
export {
|
|
98
|
+
export { UnconfirmedStop, UnconfirmedStops } from "./unconfirmed-stops.ts";
|
|
99
|
+
export { RunNotFoundError, RunOperationRejectedError, RunRetryBlockedError, EnginePersistenceError, AttemptCancellationError, RunInterventionRejectedError, LeftoversDiscardRejectedError, RunStoreError, RunEngineError, } from "./error.ts";
|
|
59
100
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine/engine.ts"],"names":[],"mappings":"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"}
|