@usine/engine 0.3.0 → 0.4.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 +109 -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 +6 -6
- package/dist/cycle-budget/cycle-budget.d.ts.map +1 -1
- package/dist/cycle-budget/cycle-budget.js +5 -5
- package/dist/cycle-budget/cycle-budget.js.map +1 -1
- package/dist/cycle-budget/model.d.ts +2 -2
- package/dist/cycle-budget/model.d.ts.map +1 -1
- package/dist/cycle-budget/model.js +2 -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 +10 -8
- package/dist/database/local-sqlite.d.ts.map +1 -1
- package/dist/database/local-sqlite.js +11 -10
- package/dist/database/local-sqlite.js.map +1 -1
- package/dist/database/schema.d.ts +533 -22
- package/dist/database/schema.d.ts.map +1 -1
- package/dist/database/schema.js +100 -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 +69 -0
- package/dist/engine/checkout-recovery.d.ts.map +1 -0
- package/dist/engine/checkout-recovery.js +181 -0
- package/dist/engine/checkout-recovery.js.map +1 -0
- package/dist/engine/engine.d.ts +55 -26
- package/dist/engine/engine.d.ts.map +1 -1
- package/dist/engine/engine.js +118 -128
- 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 +81 -28
- package/dist/engine/lifecycle.d.ts.map +1 -1
- package/dist/engine/lifecycle.js +83 -44
- 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 +54 -0
- package/dist/engine/run-driver.d.ts.map +1 -0
- package/dist/engine/run-driver.js +362 -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 +42 -12
- package/dist/engine/submission.js.map +1 -1
- package/dist/item-projection/item-projection.d.ts +12 -4
- package/dist/item-projection/item-projection.d.ts.map +1 -1
- package/dist/item-projection/item-projection.js +41 -6
- 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 +19 -9
- package/dist/run-reader/run-reader.d.ts.map +1 -1
- package/dist/run-reader/run-reader.js +23 -7
- package/dist/run-reader/run-reader.js.map +1 -1
- package/dist/step-executor.d.ts +64 -10
- 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 +207 -42
- package/dist/store/codec.d.ts.map +1 -1
- package/dist/store/codec.js +52 -14
- 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 +342 -35
- package/dist/store/queries.d.ts.map +1 -1
- package/dist/store/queries.js +302 -107
- package/dist/store/queries.js.map +1 -1
- package/dist/store/store.d.ts +91 -54
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +468 -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/package.json +15 -5
- 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
package/dist/store/queries.js
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RepositoryName } from "@usine/core/repository";
|
|
2
|
+
import { WorkerName } from "@usine/core/worker";
|
|
3
|
+
import { Attempt, AttemptId, AttemptContext, AttemptNumber } from "@usine/core/attempt";
|
|
2
4
|
import { AttemptOutcome } from "@usine/core/attempt/outcome";
|
|
5
|
+
import { AttemptSalvage, salvageRefFor } from "@usine/core/attempt/salvage";
|
|
3
6
|
import { Event, DedupKey, EventId } from "@usine/core/event";
|
|
4
7
|
import { ItemKey } from "@usine/core/item";
|
|
5
|
-
import { LoopName } from "@usine/core/loop";
|
|
8
|
+
import { LoopName, LoopPermissions } from "@usine/core/loop";
|
|
6
9
|
import { RunId } from "@usine/core/run";
|
|
7
10
|
import { StepName } from "@usine/core/step";
|
|
8
11
|
import * as RunState from "@usine/core/run/state";
|
|
9
12
|
import { StepResult } from "@usine/core/step/result";
|
|
10
|
-
import { and, asc, desc, eq, inArray, isNull, ne, notInArray, sql } from "drizzle-orm";
|
|
13
|
+
import { and, asc, desc, eq, inArray, isNull, ne, notInArray, sql, } from "drizzle-orm";
|
|
11
14
|
import { alias } from "drizzle-orm/sqlite-core";
|
|
12
15
|
import { Array as EffectArray, DateTime, Effect, Option, Schema } from "effect";
|
|
13
|
-
import { approvals, attempts, events, ignoredEvents, projectionRevision, runs, steps, triggerEvents,
|
|
16
|
+
import { approvals, attempts, events, ignoredEvents, itemCycleBudgets, loopItems, projectionRevision, runAgainEvents, runs, steps, triggerEvents, } from "../database/schema.js";
|
|
14
17
|
import { RunNotFoundError } from "../engine/error.js";
|
|
15
18
|
import { RunSnapshot, RunSummary } from "../run-reader/model.js";
|
|
16
19
|
import { Submission } from "../engine/submission.js";
|
|
17
|
-
import { WORKFLOW_COMMAND_PRIORITY } from "../workflow/command.js";
|
|
18
20
|
import { cycleQueries } from "../cycle-budget/queries.js";
|
|
19
|
-
import { attemptFromRow, decodeAttemptRows, decodeDiscards,
|
|
21
|
+
import { approvalFromRow, attemptFromRow, decodeAttemptRows, decodeDiscards, decodeNextStarts, decodeEventRoutes, decodeProjectionRevision, decodeReopenedEvents, decodeReopenings, decodeRunEventRows, decodeRunIds, decodeRunRows, encodeAgent, encodeAttemptStart, encodeBrainSpec, encodeDateTime, encodeOutcome, encodeComments, encodeSalvage, encodePayload, encodeRunState, encodeStepResult, eventFromRow, runAgainFromRow, runEventFromRow, runFromRow, runSummaryFromRow, stepFromRow, submissionFromRow, } from "./codec.js";
|
|
22
|
+
import { loopItemQueries } from "./loop-items.js";
|
|
20
23
|
import { transcriptQueries } from "./transcript.js";
|
|
21
24
|
const newestRunFirst = (left, right) => DateTime.toEpochMillis(right.openedAt) - DateTime.toEpochMillis(left.openedAt) ||
|
|
22
25
|
right.runId.localeCompare(left.runId);
|
|
@@ -29,6 +32,7 @@ const eventRouteSelection = {
|
|
|
29
32
|
loop: triggerEvents.loopName,
|
|
30
33
|
step: triggerEvents.stepName,
|
|
31
34
|
approval: triggerEvents.approval,
|
|
35
|
+
permissions: triggerEvents.permissions,
|
|
32
36
|
cycleLimit: triggerEvents.cycleLimit,
|
|
33
37
|
cycleGeneration: triggerEvents.cycleGeneration,
|
|
34
38
|
repository: triggerEvents.repository,
|
|
@@ -37,13 +41,16 @@ const eventRouteSelection = {
|
|
|
37
41
|
agent: triggerEvents.agentJson,
|
|
38
42
|
parentModel: triggerEvents.parentModel,
|
|
39
43
|
};
|
|
44
|
+
const approvalEvents = alias(events, "approval_event");
|
|
40
45
|
const runSelection = {
|
|
41
46
|
itemKey: triggerEvents.itemKey,
|
|
42
47
|
runId: runs.runId,
|
|
43
48
|
eventId: runs.eventId,
|
|
44
49
|
loop: runs.loopName,
|
|
45
50
|
state: runs.stateJson,
|
|
51
|
+
resolvedFailureAttemptId: runs.resolvedFailureAttemptId,
|
|
46
52
|
openedAt: runs.openedAt,
|
|
53
|
+
closedAt: runs.closedAt,
|
|
47
54
|
repository: runs.repository,
|
|
48
55
|
revision: runs.revision,
|
|
49
56
|
task: runs.task,
|
|
@@ -51,8 +58,13 @@ const runSelection = {
|
|
|
51
58
|
parentModel: runs.parentModel,
|
|
52
59
|
stepName: steps.stepName,
|
|
53
60
|
result: steps.result,
|
|
61
|
+
approvedAt: approvalEvents.receivedAt,
|
|
62
|
+
approvalChannel: approvals.channel,
|
|
63
|
+
approver: approvals.approver,
|
|
64
|
+
againFrom: runAgainEvents.fromRunId,
|
|
65
|
+
againRequestedBy: runAgainEvents.requestedBy,
|
|
54
66
|
};
|
|
55
|
-
const attemptSelection = {
|
|
67
|
+
export const attemptSelection = {
|
|
56
68
|
attemptId: attempts.attemptId,
|
|
57
69
|
runId: attempts.runId,
|
|
58
70
|
stepName: attempts.stepName,
|
|
@@ -65,8 +77,12 @@ const attemptSelection = {
|
|
|
65
77
|
parentModel: attempts.parentModel,
|
|
66
78
|
startedAt: attempts.startedAt,
|
|
67
79
|
outcome: attempts.outcomeJson,
|
|
80
|
+
endedAt: attempts.endedAt,
|
|
81
|
+
salvage: attempts.salvageJson,
|
|
82
|
+
start: attempts.startJson,
|
|
83
|
+
reattachedAt: attempts.reattachedAt,
|
|
84
|
+
comments: attempts.commentsJson,
|
|
68
85
|
};
|
|
69
|
-
// The state partitions are owned by @usine/core; these predicates only borrow their tags.
|
|
70
86
|
const storedStateTag = sql `json_extract(${runs.stateJson}, '$._tag')`;
|
|
71
87
|
const openState = inArray(storedStateTag, [...RunState.OPEN_STATE_TAGS]);
|
|
72
88
|
const unstartedState = inArray(storedStateTag, [...RunState.UNSTARTED_STATE_TAGS]);
|
|
@@ -74,8 +90,7 @@ const unstartedState = inArray(storedStateTag, [...RunState.UNSTARTED_STATE_TAGS
|
|
|
74
90
|
// cannot emit the declaration (TS2883).
|
|
75
91
|
const storedAgent = (agent) => Schema.decodeUnknownSync(Schema.Json)(encodeAgent(agent));
|
|
76
92
|
export const queriesFor = (database) => {
|
|
77
|
-
//
|
|
78
|
-
// Workflow suspension before its final mutation is observable (ADR 0020).
|
|
93
|
+
// `.execute()` stays explicit (ADR 0020).
|
|
79
94
|
const eventRouteByDedup = Effect.fn("RunStoreQueries.eventRouteByDedup")(function* (dedupKey) {
|
|
80
95
|
const rows = yield* database
|
|
81
96
|
.select(eventRouteSelection)
|
|
@@ -95,15 +110,57 @@ export const queriesFor = (database) => {
|
|
|
95
110
|
.execute();
|
|
96
111
|
return yield* decodeEventRoutes(rows);
|
|
97
112
|
});
|
|
113
|
+
const selectRuns = () => database
|
|
114
|
+
.select(runSelection)
|
|
115
|
+
.from(runs)
|
|
116
|
+
.innerJoin(triggerEvents, eq(triggerEvents.eventId, runs.eventId))
|
|
117
|
+
.innerJoin(steps, eq(steps.runId, runs.runId))
|
|
118
|
+
.leftJoin(approvals, eq(approvals.runId, runs.runId))
|
|
119
|
+
.leftJoin(approvalEvents, eq(approvalEvents.eventId, approvals.eventId))
|
|
120
|
+
.leftJoin(runAgainEvents, eq(runAgainEvents.eventId, runs.eventId));
|
|
98
121
|
const runRows = Effect.fn("RunStoreQueries.runRows")(function* (runId) {
|
|
122
|
+
const rows = yield* selectRuns().where(eq(runs.runId, runId)).execute();
|
|
123
|
+
return yield* decodeRunRows(rows);
|
|
124
|
+
});
|
|
125
|
+
/** Returns the Attempts that match `filters` and whose leftovers weren't discarded. */
|
|
126
|
+
const recoveries = (...filters) => Effect.gen(function* () {
|
|
99
127
|
const rows = yield* database
|
|
100
|
-
.select(
|
|
101
|
-
.
|
|
128
|
+
.select({
|
|
129
|
+
attemptId: attempts.attemptId,
|
|
130
|
+
worker: attempts.workerName,
|
|
131
|
+
repository: runs.repository,
|
|
132
|
+
runId: attempts.runId,
|
|
133
|
+
number: attempts.attemptNumber,
|
|
134
|
+
permissions: triggerEvents.permissions,
|
|
135
|
+
outcome: sql `coalesce(json_extract(${attempts.outcomeJson}, '$._tag'), '')`,
|
|
136
|
+
})
|
|
137
|
+
.from(attempts)
|
|
138
|
+
.innerJoin(runs, eq(runs.runId, attempts.runId))
|
|
102
139
|
.innerJoin(triggerEvents, eq(triggerEvents.eventId, runs.eventId))
|
|
103
|
-
.
|
|
104
|
-
.where(eq(runs.runId, runId))
|
|
140
|
+
.where(and(isNull(attempts.leftoversDiscardedAt), ...filters))
|
|
105
141
|
.execute();
|
|
106
|
-
|
|
142
|
+
const decoded = yield* Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({
|
|
143
|
+
attemptId: AttemptId,
|
|
144
|
+
worker: WorkerName,
|
|
145
|
+
repository: RepositoryName,
|
|
146
|
+
runId: RunId,
|
|
147
|
+
number: AttemptNumber,
|
|
148
|
+
permissions: LoopPermissions,
|
|
149
|
+
outcome: Schema.String,
|
|
150
|
+
})))(rows);
|
|
151
|
+
return decoded.map(({ runId, number, outcome, ...attempt }) => ({
|
|
152
|
+
...attempt,
|
|
153
|
+
ref: salvageRefFor(runId, number),
|
|
154
|
+
succeeded: outcome === "Succeeded",
|
|
155
|
+
open: outcome === "",
|
|
156
|
+
}));
|
|
157
|
+
});
|
|
158
|
+
const salvageCandidates = Effect.fn("RunStoreQueries.salvageCandidates")(function* () {
|
|
159
|
+
return yield* recoveries();
|
|
160
|
+
});
|
|
161
|
+
const salvageCandidate = Effect.fn("RunStoreQueries.salvageCandidate")(function* (attemptId) {
|
|
162
|
+
yield* Effect.annotateCurrentSpan({ attemptId });
|
|
163
|
+
return EffectArray.head(yield* recoveries(eq(attempts.attemptId, attemptId)));
|
|
107
164
|
});
|
|
108
165
|
const attemptRows = Effect.fn("RunStoreQueries.attemptRows")(function* (runId) {
|
|
109
166
|
const rows = yield* database
|
|
@@ -131,17 +188,21 @@ export const queriesFor = (database) => {
|
|
|
131
188
|
run: runFromRow(storedRun),
|
|
132
189
|
step: stepFromRow(storedRun),
|
|
133
190
|
attempts: storedAttempts.map(attemptFromRow),
|
|
191
|
+
resolvedFailureAttemptId: Option.fromNullishOr(storedRun.resolvedFailureAttemptId),
|
|
192
|
+
closedAt: Option.fromNullishOr(storedRun.closedAt),
|
|
193
|
+
approval: approvalFromRow(storedRun),
|
|
194
|
+
runAgain: runAgainFromRow(storedRun),
|
|
134
195
|
repository: storedRun.repository,
|
|
135
196
|
revision: storedRun.revision,
|
|
136
197
|
task: storedRun.task,
|
|
137
198
|
agent: storedRun.agent,
|
|
138
199
|
parentModel: Option.fromNullishOr(storedRun.parentModel),
|
|
200
|
+
permissions: route.permissions,
|
|
139
201
|
});
|
|
140
202
|
});
|
|
141
203
|
const summariesWithAttempts = Effect.fn("RunStoreQueries.summariesWithAttempts")(function* (storedRuns) {
|
|
142
204
|
const runIds = storedRuns.map(({ runId }) => runId);
|
|
143
|
-
//
|
|
144
|
-
// long-lived Task with many Runs.
|
|
205
|
+
// Chunks keep each read below the driver's bind-parameter limit.
|
|
145
206
|
const storedAttempts = (yield* Effect.forEach(EffectArray.chunksOf(runIds, 100), (ids) => database
|
|
146
207
|
.select(attemptSelection)
|
|
147
208
|
.from(attempts)
|
|
@@ -155,11 +216,7 @@ export const queriesFor = (database) => {
|
|
|
155
216
|
const itemRunSummaries = Effect.fn("RunStoreQueries.itemRunSummaries")(function* (itemKeys) {
|
|
156
217
|
if (itemKeys.length === 0)
|
|
157
218
|
return [];
|
|
158
|
-
const storedRuns = (yield* Effect.forEach(EffectArray.chunksOf([...new Set(itemKeys)], 100), (keys) =>
|
|
159
|
-
.select(runSelection)
|
|
160
|
-
.from(runs)
|
|
161
|
-
.innerJoin(triggerEvents, eq(triggerEvents.eventId, runs.eventId))
|
|
162
|
-
.innerJoin(steps, eq(steps.runId, runs.runId))
|
|
219
|
+
const storedRuns = (yield* Effect.forEach(EffectArray.chunksOf([...new Set(itemKeys)], 100), (keys) => selectRuns()
|
|
163
220
|
.where(inArray(triggerEvents.itemKey, keys))
|
|
164
221
|
.execute()
|
|
165
222
|
.pipe(Effect.flatMap(decodeRunRows))))
|
|
@@ -167,24 +224,15 @@ export const queriesFor = (database) => {
|
|
|
167
224
|
.sort(newestRunFirst);
|
|
168
225
|
return yield* summariesWithAttempts(storedRuns);
|
|
169
226
|
});
|
|
170
|
-
// Every open Run plus the newest `closedLimit`
|
|
171
|
-
// Waiting run never falls out of the operator's view while history stays bounded.
|
|
227
|
+
// Every open Run plus the newest `closedLimit` closed ones, so an old waiting Run stays listed.
|
|
172
228
|
const runSummaries = Effect.fn("RunStoreQueries.runSummaries")(function* (closedLimit) {
|
|
173
229
|
const [openRuns, closedRuns] = yield* Effect.all([
|
|
174
|
-
|
|
175
|
-
.select(runSelection)
|
|
176
|
-
.from(runs)
|
|
177
|
-
.innerJoin(triggerEvents, eq(triggerEvents.eventId, runs.eventId))
|
|
178
|
-
.innerJoin(steps, eq(steps.runId, runs.runId))
|
|
230
|
+
selectRuns()
|
|
179
231
|
.where(openState)
|
|
180
232
|
.orderBy(desc(runs.openedAt), desc(runs.runId))
|
|
181
233
|
.execute()
|
|
182
234
|
.pipe(Effect.flatMap(decodeRunRows)),
|
|
183
|
-
|
|
184
|
-
.select(runSelection)
|
|
185
|
-
.from(runs)
|
|
186
|
-
.innerJoin(triggerEvents, eq(triggerEvents.eventId, runs.eventId))
|
|
187
|
-
.innerJoin(steps, eq(steps.runId, runs.runId))
|
|
235
|
+
selectRuns()
|
|
188
236
|
.where(notInArray(storedStateTag, [...RunState.OPEN_STATE_TAGS]))
|
|
189
237
|
.orderBy(desc(runs.openedAt), desc(runs.runId))
|
|
190
238
|
.limit(closedLimit)
|
|
@@ -194,6 +242,32 @@ export const queriesFor = (database) => {
|
|
|
194
242
|
const storedRuns = [...openRuns, ...closedRuns].sort(newestRunFirst);
|
|
195
243
|
return yield* summariesWithAttempts(storedRuns);
|
|
196
244
|
});
|
|
245
|
+
const runEvents = Effect.fn("RunStoreQueries.runEvents")(function* (runIds) {
|
|
246
|
+
// Chunks keep each read below the driver's bind-parameter limit.
|
|
247
|
+
const rows = yield* Effect.forEach(EffectArray.chunksOf([...new Set(runIds)], 100), (ids) => database
|
|
248
|
+
.select({
|
|
249
|
+
runId: runs.runId,
|
|
250
|
+
eventId: events.eventId,
|
|
251
|
+
dedupKey: events.dedupKey,
|
|
252
|
+
payload: events.payloadJson,
|
|
253
|
+
receivedAt: events.receivedAt,
|
|
254
|
+
})
|
|
255
|
+
.from(runs)
|
|
256
|
+
.innerJoin(events, eq(events.eventId, runs.eventId))
|
|
257
|
+
.where(inArray(runs.runId, ids))
|
|
258
|
+
.execute()
|
|
259
|
+
.pipe(Effect.flatMap(decodeRunEventRows)));
|
|
260
|
+
return rows.flat().map(runEventFromRow);
|
|
261
|
+
});
|
|
262
|
+
const closedRunSummaries = Effect.fn("RunStoreQueries.closedRunSummaries")(function* (limit) {
|
|
263
|
+
const closedRuns = yield* selectRuns()
|
|
264
|
+
.where(notInArray(storedStateTag, [...RunState.OPEN_STATE_TAGS]))
|
|
265
|
+
.orderBy(desc(runs.closedAt), desc(runs.runId))
|
|
266
|
+
.limit(limit)
|
|
267
|
+
.execute()
|
|
268
|
+
.pipe(Effect.flatMap(decodeRunRows));
|
|
269
|
+
return yield* summariesWithAttempts(closedRuns);
|
|
270
|
+
});
|
|
197
271
|
const revision = Effect.fn("RunStoreQueries.projectionRevision")(function* () {
|
|
198
272
|
const rows = yield* decodeProjectionRevision(yield* database
|
|
199
273
|
.select({ revision: projectionRevision.revision })
|
|
@@ -203,10 +277,12 @@ export const queriesFor = (database) => {
|
|
|
203
277
|
.execute());
|
|
204
278
|
return Option.fromNullishOr(rows[0]?.revision);
|
|
205
279
|
});
|
|
206
|
-
|
|
280
|
+
// A closed state sets `closedAt` to `at` or now; an open state clears it.
|
|
281
|
+
const updateState = Effect.fn("RunStoreQueries.updateState")(function* (runId, state, at) {
|
|
282
|
+
const closedAt = RunState.isOpen(state) ? null : encodeDateTime(at ?? (yield* DateTime.now));
|
|
207
283
|
const updated = yield* database
|
|
208
284
|
.update(runs)
|
|
209
|
-
.set({ stateJson: encodeRunState(state) })
|
|
285
|
+
.set({ stateJson: encodeRunState(state), closedAt })
|
|
210
286
|
.where(eq(runs.runId, runId))
|
|
211
287
|
.returning({ runId: runs.runId })
|
|
212
288
|
.execute();
|
|
@@ -214,6 +290,14 @@ export const queriesFor = (database) => {
|
|
|
214
290
|
return yield* new RunNotFoundError({ runId });
|
|
215
291
|
}
|
|
216
292
|
});
|
|
293
|
+
const resolveFailure = Effect.fn("RunStoreQueries.resolveFailure")(function* (runId, attemptId) {
|
|
294
|
+
yield* Effect.annotateCurrentSpan({ runId, attemptId });
|
|
295
|
+
yield* database
|
|
296
|
+
.update(runs)
|
|
297
|
+
.set({ resolvedFailureAttemptId: attemptId })
|
|
298
|
+
.where(eq(runs.runId, runId))
|
|
299
|
+
.execute();
|
|
300
|
+
});
|
|
217
301
|
const addAttempt = Effect.fn("RunStoreQueries.addAttempt")(function* (attempt) {
|
|
218
302
|
yield* database
|
|
219
303
|
.insert(attempts)
|
|
@@ -230,13 +314,58 @@ export const queriesFor = (database) => {
|
|
|
230
314
|
parentModel: Option.getOrNull(attempt.parentModel),
|
|
231
315
|
startedAt: encodeDateTime(attempt.startedAt),
|
|
232
316
|
outcomeJson: null,
|
|
317
|
+
endedAt: null,
|
|
318
|
+
salvageJson: null,
|
|
319
|
+
startJson: Option.match(attempt.start, { onNone: () => null, onSome: encodeAttemptStart }),
|
|
233
320
|
})
|
|
234
321
|
.execute();
|
|
235
322
|
});
|
|
236
|
-
const
|
|
323
|
+
const recordReattach = Effect.fn("RunStoreQueries.recordReattach")(function* (attemptId, reattachedAt) {
|
|
324
|
+
yield* Effect.annotateCurrentSpan({ attemptId });
|
|
237
325
|
yield* database
|
|
238
326
|
.update(attempts)
|
|
239
|
-
.set({
|
|
327
|
+
.set({ reattachedAt: encodeDateTime(reattachedAt) })
|
|
328
|
+
.where(eq(attempts.attemptId, attemptId))
|
|
329
|
+
.execute();
|
|
330
|
+
});
|
|
331
|
+
/** Returns the operator retry for the Run's next Attempt, or `None`. */
|
|
332
|
+
const nextStart = Effect.fn("RunStoreQueries.nextStart")(function* (runId) {
|
|
333
|
+
const rows = yield* database
|
|
334
|
+
.select({ nextStart: runs.nextStartJson })
|
|
335
|
+
.from(runs)
|
|
336
|
+
.where(eq(runs.runId, runId))
|
|
337
|
+
.execute();
|
|
338
|
+
return Option.fromNullishOr((yield* decodeNextStarts(rows))[0]?.nextStart);
|
|
339
|
+
});
|
|
340
|
+
const setNextStart = Effect.fn("RunStoreQueries.setNextStart")(function* (runId, start) {
|
|
341
|
+
yield* database
|
|
342
|
+
.update(runs)
|
|
343
|
+
.set({
|
|
344
|
+
nextStartJson: Option.match(start, { onNone: () => null, onSome: encodeAttemptStart }),
|
|
345
|
+
})
|
|
346
|
+
.where(eq(runs.runId, runId))
|
|
347
|
+
.execute();
|
|
348
|
+
});
|
|
349
|
+
const recordSalvage = Effect.fn("RunStoreQueries.recordSalvage")(function* (attemptId, salvage) {
|
|
350
|
+
yield* Effect.annotateCurrentSpan({ attemptId, salvage: salvage._tag });
|
|
351
|
+
yield* database
|
|
352
|
+
.update(attempts)
|
|
353
|
+
.set({ salvageJson: encodeSalvage(salvage) })
|
|
354
|
+
.where(eq(attempts.attemptId, attemptId))
|
|
355
|
+
.execute();
|
|
356
|
+
});
|
|
357
|
+
const recordComments = Effect.fn("RunStoreQueries.recordComments")(function* (attemptId, comments) {
|
|
358
|
+
yield* Effect.annotateCurrentSpan({ attemptId, comments: comments.length });
|
|
359
|
+
yield* database
|
|
360
|
+
.update(attempts)
|
|
361
|
+
.set({ commentsJson: encodeComments(comments) })
|
|
362
|
+
.where(eq(attempts.attemptId, attemptId))
|
|
363
|
+
.execute();
|
|
364
|
+
});
|
|
365
|
+
const closeAttempt = Effect.fn("RunStoreQueries.closeAttempt")(function* (attemptId, outcome, endedAt) {
|
|
366
|
+
yield* database
|
|
367
|
+
.update(attempts)
|
|
368
|
+
.set({ outcomeJson: encodeOutcome(outcome), endedAt: encodeDateTime(endedAt) })
|
|
240
369
|
.where(and(eq(attempts.attemptId, attemptId), isNull(attempts.outcomeJson)))
|
|
241
370
|
.execute();
|
|
242
371
|
});
|
|
@@ -277,7 +406,7 @@ export const queriesFor = (database) => {
|
|
|
277
406
|
const approvalExists = Effect.fn("RunStoreQueries.approvalExists")(function* (runId) {
|
|
278
407
|
return (yield* database.$count(approvals, eq(approvals.runId, runId)).execute()) > 0;
|
|
279
408
|
});
|
|
280
|
-
const recordApproval = Effect.fn("RunStoreQueries.recordApproval")(function* (runId, approval) {
|
|
409
|
+
const recordApproval = Effect.fn("RunStoreQueries.recordApproval")(function* (runId, approval, source) {
|
|
281
410
|
yield* database
|
|
282
411
|
.insert(events)
|
|
283
412
|
.values({
|
|
@@ -288,30 +417,15 @@ export const queriesFor = (database) => {
|
|
|
288
417
|
})
|
|
289
418
|
.onConflictDoNothing()
|
|
290
419
|
.execute();
|
|
291
|
-
yield* database.insert(approvals).values({ runId, eventId: approval.id }).execute();
|
|
292
|
-
});
|
|
293
|
-
const requestWorkflowCommand = Effect.fn("RunStoreQueries.requestWorkflowCommand")(function* (runId, command) {
|
|
294
|
-
yield* database
|
|
295
|
-
.insert(workflowCommands)
|
|
296
|
-
.values({ runId, command })
|
|
297
|
-
.onConflictDoNothing()
|
|
298
|
-
.execute();
|
|
299
|
-
});
|
|
300
|
-
const requestInterrupt = Effect.fn("RunStoreQueries.requestInterrupt")(function* (runId) {
|
|
301
420
|
yield* database
|
|
302
|
-
.
|
|
303
|
-
.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const rows = yield* database
|
|
310
|
-
.select({ runId: workflowCommands.runId, command: workflowCommands.command })
|
|
311
|
-
.from(workflowCommands)
|
|
312
|
-
.where(eq(workflowCommands.runId, runId))
|
|
421
|
+
.insert(approvals)
|
|
422
|
+
.values({
|
|
423
|
+
runId,
|
|
424
|
+
eventId: approval.id,
|
|
425
|
+
channel: source.channel,
|
|
426
|
+
approver: Option.getOrNull(source.approver),
|
|
427
|
+
})
|
|
313
428
|
.execute();
|
|
314
|
-
return (yield* decodeWorkflowCommands(rows)).map(({ command }) => command);
|
|
315
429
|
});
|
|
316
430
|
const createRun = Effect.fn("RunStoreQueries.createRun")(function* (submission, eventId, runId) {
|
|
317
431
|
const candidate = alias(triggerEvents, "candidate");
|
|
@@ -376,7 +490,48 @@ export const queriesFor = (database) => {
|
|
|
376
490
|
.limit(1)
|
|
377
491
|
.execute());
|
|
378
492
|
});
|
|
379
|
-
|
|
493
|
+
/** Returns the newest reopening of `eventId` (#267), with its reopening number. */
|
|
494
|
+
const newestReopening = Effect.fn("RunStoreQueries.newestReopening")(function* (eventId) {
|
|
495
|
+
const rows = yield* decodeReopenings(yield* database
|
|
496
|
+
.select({ ...eventRouteSelection, reopening: triggerEvents.reopening })
|
|
497
|
+
.from(events)
|
|
498
|
+
.innerJoin(triggerEvents, eq(triggerEvents.eventId, events.eventId))
|
|
499
|
+
.where(eq(triggerEvents.reopensEventId, eventId))
|
|
500
|
+
.orderBy(desc(triggerEvents.reopening))
|
|
501
|
+
.limit(1)
|
|
502
|
+
.execute());
|
|
503
|
+
return Option.map(Option.fromNullishOr(rows[0]), (row) => ({
|
|
504
|
+
submission: submissionFromRow(row),
|
|
505
|
+
reopening: row.reopening,
|
|
506
|
+
}));
|
|
507
|
+
});
|
|
508
|
+
/** Returns the trigger Event that `eventId` reopens or runs again, or `None` for a trigger's own Event. */
|
|
509
|
+
const reopenedEvent = Effect.fn("RunStoreQueries.reopenedEvent")(function* (eventId) {
|
|
510
|
+
const reopened = alias(events, "reopened_event");
|
|
511
|
+
const rows = yield* decodeReopenedEvents(yield* database
|
|
512
|
+
.select({ eventId: reopened.eventId, dedupKey: reopened.dedupKey })
|
|
513
|
+
.from(triggerEvents)
|
|
514
|
+
.innerJoin(reopened, eq(reopened.eventId, triggerEvents.reopensEventId))
|
|
515
|
+
.where(eq(triggerEvents.eventId, eventId))
|
|
516
|
+
.execute());
|
|
517
|
+
return Option.fromNullishOr(rows[0]);
|
|
518
|
+
});
|
|
519
|
+
/** Records that `eventId` came from running a closed Run again, and the requesting login. */
|
|
520
|
+
const recordRunAgain = Effect.fn("RunStoreQueries.recordRunAgain")(function* (eventId, again) {
|
|
521
|
+
yield* database
|
|
522
|
+
.insert(runAgainEvents)
|
|
523
|
+
.values({
|
|
524
|
+
eventId,
|
|
525
|
+
fromRunId: again.from,
|
|
526
|
+
requestedBy: Option.getOrNull(again.requestedBy),
|
|
527
|
+
})
|
|
528
|
+
.execute();
|
|
529
|
+
});
|
|
530
|
+
/**
|
|
531
|
+
* Records a trigger Event and its route once, and returns the route as first recorded.
|
|
532
|
+
* `reopens` is the earlier Event that this one reopens.
|
|
533
|
+
*/
|
|
534
|
+
const recordTriggerEvent = Effect.fn("RunStoreQueries.recordTriggerEvent")(function* (submission, reopens = Option.none()) {
|
|
380
535
|
yield* database
|
|
381
536
|
.insert(events)
|
|
382
537
|
.values({
|
|
@@ -398,6 +553,7 @@ export const queriesFor = (database) => {
|
|
|
398
553
|
loopName: submission.loop,
|
|
399
554
|
stepName: submission.step,
|
|
400
555
|
approval: submission.approval,
|
|
556
|
+
permissions: submission.permissions,
|
|
401
557
|
cycleLimit: Option.getOrNull(submission.cycleLimit),
|
|
402
558
|
cycleGeneration: submission.cycleGeneration,
|
|
403
559
|
repository: submission.repository,
|
|
@@ -405,6 +561,11 @@ export const queriesFor = (database) => {
|
|
|
405
561
|
task: submission.task,
|
|
406
562
|
agentJson: storedAgent(submission.agent),
|
|
407
563
|
parentModel: Option.getOrNull(submission.parentModel),
|
|
564
|
+
reopensEventId: Option.getOrNull(Option.map(reopens, ({ eventId }) => eventId)),
|
|
565
|
+
reopening: Option.match(reopens, {
|
|
566
|
+
onNone: () => 0,
|
|
567
|
+
onSome: ({ reopening }) => reopening,
|
|
568
|
+
}),
|
|
408
569
|
})
|
|
409
570
|
.execute();
|
|
410
571
|
return submission;
|
|
@@ -416,6 +577,16 @@ export const queriesFor = (database) => {
|
|
|
416
577
|
const current = routes[0];
|
|
417
578
|
if (current === undefined)
|
|
418
579
|
return Option.none();
|
|
580
|
+
const suppression = yield* loopItemQueries(database).suppression(current.loop, current.itemKey);
|
|
581
|
+
if (Option.isSome(suppression)) {
|
|
582
|
+
yield* Effect.logInfo("Queued Events wait while a suppression keeps the Item", {
|
|
583
|
+
runId,
|
|
584
|
+
suppressedBy: suppression.value.runId,
|
|
585
|
+
loop: current.loop,
|
|
586
|
+
itemKey: current.itemKey,
|
|
587
|
+
});
|
|
588
|
+
return Option.none();
|
|
589
|
+
}
|
|
419
590
|
const queuedRows = yield* database
|
|
420
591
|
.select(eventRouteSelection)
|
|
421
592
|
.from(events)
|
|
@@ -424,55 +595,53 @@ export const queriesFor = (database) => {
|
|
|
424
595
|
.leftJoin(ignoredEvents, eq(ignoredEvents.eventId, events.eventId))
|
|
425
596
|
.where(and(eq(triggerEvents.loopName, current.loop), eq(triggerEvents.itemKey, current.itemKey), cycleQueries(database).currentEvent, isNull(runs.runId), isNull(ignoredEvents.eventId)))
|
|
426
597
|
.orderBy(desc(events.receivedAt))
|
|
427
|
-
.limit(1)
|
|
428
598
|
.execute();
|
|
429
599
|
const queued = yield* decodeEventRoutes(queuedRows);
|
|
430
|
-
return Option.fromNullishOr(queued[0]).pipe(Option.map(
|
|
600
|
+
return Option.fromNullishOr(queued[0]).pipe(Option.map((newest) => ({
|
|
601
|
+
submission: submissionFromRow(newest),
|
|
602
|
+
eventIds: queued.map((row) => row.eventId),
|
|
603
|
+
})));
|
|
431
604
|
});
|
|
432
|
-
const
|
|
605
|
+
const runIdsToDrive = Effect.fn("RunStoreQueries.runIdsToDrive")(function* () {
|
|
606
|
+
const waiting = "Waiting";
|
|
433
607
|
const rows = yield* database
|
|
434
|
-
.select({
|
|
435
|
-
...eventRouteSelection,
|
|
436
|
-
runId: runs.runId,
|
|
437
|
-
state: runs.stateJson,
|
|
438
|
-
})
|
|
608
|
+
.select({ runId: runs.runId })
|
|
439
609
|
.from(runs)
|
|
440
|
-
.
|
|
441
|
-
.innerJoin(triggerEvents, eq(triggerEvents.eventId, events.eventId))
|
|
442
|
-
.where(openState)
|
|
610
|
+
.where(and(openState, ne(storedStateTag, waiting)))
|
|
443
611
|
.execute();
|
|
444
|
-
return yield*
|
|
612
|
+
return (yield* decodeRunIds(rows)).map(({ runId }) => runId);
|
|
445
613
|
});
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
? -1
|
|
458
|
-
: 1);
|
|
459
|
-
});
|
|
460
|
-
const completeWorkflowCommand = Effect.fn("RunStoreQueries.completeWorkflowCommand")(function* (runId, command) {
|
|
461
|
-
yield* database
|
|
462
|
-
.delete(workflowCommands)
|
|
463
|
-
.where(and(eq(workflowCommands.runId, runId), eq(workflowCommands.command, command)))
|
|
614
|
+
// The newest closed Run of each Item that has a current queued Event and no open Run, excluding
|
|
615
|
+
// Items waiting for a cycle-budget reset or under a suppression.
|
|
616
|
+
const pendingContinuations = Effect.fn("RunStoreQueries.pendingContinuations")(function* () {
|
|
617
|
+
const items = yield* database
|
|
618
|
+
.selectDistinct({ loop: triggerEvents.loopName, itemKey: triggerEvents.itemKey })
|
|
619
|
+
.from(triggerEvents)
|
|
620
|
+
.leftJoin(runs, eq(runs.eventId, triggerEvents.eventId))
|
|
621
|
+
.leftJoin(ignoredEvents, eq(ignoredEvents.eventId, triggerEvents.eventId))
|
|
622
|
+
.leftJoin(itemCycleBudgets, eq(itemCycleBudgets.itemKey, triggerEvents.itemKey))
|
|
623
|
+
.leftJoin(loopItems, and(eq(loopItems.loopName, triggerEvents.loopName), eq(loopItems.itemKey, triggerEvents.itemKey)))
|
|
624
|
+
.where(and(isNull(runs.runId), isNull(ignoredEvents.eventId), isNull(itemCycleBudgets.askJson), isNull(loopItems.suppressedByRunId), cycleQueries(database).currentEvent))
|
|
464
625
|
.execute();
|
|
626
|
+
const decoded = yield* Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ loop: LoopName, itemKey: ItemKey })))(items);
|
|
627
|
+
const closed = yield* Effect.forEach(decoded, ({ loop, itemKey }) => Effect.gen(function* () {
|
|
628
|
+
if ((yield* blockingRun(loop, itemKey)).length > 0)
|
|
629
|
+
return [];
|
|
630
|
+
return yield* decodeRunIds(yield* database
|
|
631
|
+
.select({ runId: runs.runId })
|
|
632
|
+
.from(runs)
|
|
633
|
+
.innerJoin(triggerEvents, eq(triggerEvents.eventId, runs.eventId))
|
|
634
|
+
.where(and(eq(triggerEvents.loopName, loop), eq(triggerEvents.itemKey, itemKey)))
|
|
635
|
+
.orderBy(desc(runs.openedAt), desc(runs.runId))
|
|
636
|
+
.limit(1)
|
|
637
|
+
.execute());
|
|
638
|
+
}));
|
|
639
|
+
return closed.flat().map(({ runId }) => runId);
|
|
465
640
|
});
|
|
466
|
-
const
|
|
467
|
-
const rows = yield* decodeRunIds(yield* database
|
|
468
|
-
.select({ runId: runs.runId })
|
|
469
|
-
.from(runs)
|
|
470
|
-
.innerJoin(triggerEvents, eq(triggerEvents.eventId, runs.eventId))
|
|
471
|
-
.where(and(eq(triggerEvents.loopName, loop), eq(triggerEvents.itemKey, itemKey), unstartedState))
|
|
472
|
-
.execute());
|
|
641
|
+
const revokeQueued = Effect.fn("RunStoreQueries.revokeQueued")(function* (loop, itemKey, eventIds) {
|
|
473
642
|
const candidate = alias(triggerEvents, "candidate");
|
|
474
643
|
const candidateRun = alias(runs, "candidate_run");
|
|
475
|
-
yield* database
|
|
644
|
+
const ignored = yield* database
|
|
476
645
|
.insert(ignoredEvents)
|
|
477
646
|
.select(database
|
|
478
647
|
.select({
|
|
@@ -481,41 +650,67 @@ export const queriesFor = (database) => {
|
|
|
481
650
|
})
|
|
482
651
|
.from(candidate)
|
|
483
652
|
.leftJoin(candidateRun, eq(candidateRun.eventId, candidate.eventId))
|
|
484
|
-
.where(and(eq(candidate.loopName, loop), eq(candidate.itemKey, itemKey), isNull(candidateRun.runId))))
|
|
653
|
+
.where(and(eq(candidate.loopName, loop), eq(candidate.itemKey, itemKey), inArray(candidate.eventId, eventIds), isNull(candidateRun.runId))))
|
|
485
654
|
.onConflictDoNothing()
|
|
655
|
+
.returning({ eventId: ignoredEvents.eventId })
|
|
486
656
|
.execute();
|
|
657
|
+
return ignored.length;
|
|
658
|
+
});
|
|
659
|
+
const revokeUnstarted = Effect.fn("RunStoreQueries.revokeUnstarted")(function* (loop, itemKey) {
|
|
660
|
+
const rows = yield* decodeRunIds(yield* database
|
|
661
|
+
.select({ runId: runs.runId })
|
|
662
|
+
.from(runs)
|
|
663
|
+
.innerJoin(triggerEvents, eq(triggerEvents.eventId, runs.eventId))
|
|
664
|
+
.where(and(eq(triggerEvents.loopName, loop), eq(triggerEvents.itemKey, itemKey), unstartedState))
|
|
665
|
+
.execute());
|
|
666
|
+
const queued = database
|
|
667
|
+
.select({ eventId: triggerEvents.eventId })
|
|
668
|
+
.from(triggerEvents)
|
|
669
|
+
.where(and(eq(triggerEvents.loopName, loop), eq(triggerEvents.itemKey, itemKey)));
|
|
670
|
+
yield* revokeQueued(loop, itemKey, queued);
|
|
487
671
|
return rows;
|
|
488
672
|
});
|
|
489
673
|
return {
|
|
674
|
+
salvageCandidates,
|
|
675
|
+
salvageCandidate,
|
|
490
676
|
cycles: cycleQueries(database),
|
|
677
|
+
loopItems: loopItemQueries(database),
|
|
491
678
|
...transcriptQueries(database),
|
|
492
679
|
addAttempt,
|
|
680
|
+
recordReattach,
|
|
681
|
+
nextStart,
|
|
682
|
+
setNextStart,
|
|
683
|
+
recordSalvage,
|
|
684
|
+
recordComments,
|
|
493
685
|
amend,
|
|
494
686
|
markIntervened,
|
|
495
687
|
approvalExists,
|
|
496
688
|
blockingRun,
|
|
497
689
|
closeAttempt,
|
|
498
|
-
completeWorkflowCommand,
|
|
499
690
|
createRun,
|
|
500
691
|
eventRouteByRun,
|
|
501
|
-
workflowCommandsFor,
|
|
502
692
|
ignoredEvent,
|
|
693
|
+
newestReopening,
|
|
503
694
|
nextQueued,
|
|
504
|
-
|
|
695
|
+
reopenedEvent,
|
|
696
|
+
recordRunAgain,
|
|
697
|
+
pendingContinuations,
|
|
505
698
|
recordTriggerEvent,
|
|
506
|
-
|
|
699
|
+
runIdsToDrive,
|
|
507
700
|
recordApproval,
|
|
508
|
-
requestInterrupt,
|
|
509
|
-
requestWorkflowCommand,
|
|
510
701
|
revision,
|
|
702
|
+
revokeQueued,
|
|
511
703
|
revokeUnstarted,
|
|
512
704
|
runSummaries,
|
|
705
|
+
closedRunSummaries,
|
|
513
706
|
itemRunSummaries,
|
|
707
|
+
runEvents,
|
|
514
708
|
runForEvent,
|
|
515
709
|
snapshot,
|
|
516
710
|
updateStepResult,
|
|
517
711
|
updateAttemptParentModel,
|
|
518
712
|
updateState,
|
|
713
|
+
resolveFailure,
|
|
519
714
|
};
|
|
520
715
|
};
|
|
521
716
|
//# sourceMappingURL=queries.js.map
|