@tenetkit/pg 0.38.0 → 0.38.2

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.
@@ -17,5 +17,5 @@ export declare const postgresOperations: (input: {
17
17
  readonly requireRun: (runId: string) => Effect.Effect<DecodedRun, RunNotFound | RuntimeUnavailable | SqlError, SqlR>;
18
18
  readonly requireClaim: (claim: import("tenetkit/runtime/driver/run-store").ExecutionClaim) => Effect.Effect<void, import("tenetkit/runtime/driver/sql/errors").StaleClaim | RunNotFound | RuntimeUnavailable | SqlError, SqlR>;
19
19
  readonly nextId: (prefix: string) => Effect.Effect<string>;
20
- }) => Pick<RunStoreInterface, "recordOperation" | "startOperation" | "completeOperation" | "commitModelResponse" | "commitInterruptedModelResponse" | "expireRunningOperation" | "getOperation" | "getOperationByKey" | "resolveOperation">;
20
+ }) => Pick<RunStoreInterface, "recordOperation" | "startOperation" | "completeOperation" | "commitModelResponse" | "commitInterruptedModelResponse" | "expireRunningOperation" | "recoverRunningOperations" | "getOperation" | "getOperationByKey" | "resolveOperation">;
21
21
  export {};
@@ -18,6 +18,38 @@ import { lockRunHierarchy } from "./locks.js";
18
18
  export const postgresOperations = (input) => {
19
19
  const { sql, hub, run, runNoTxn, requireRun, requireClaim, nextId } = input;
20
20
  const fenced = (claim, effect) => run(sql `SELECT run_id FROM tenetkit_runs WHERE run_id = ${claim.runId} FOR UPDATE`.pipe(Effect.andThen(requireClaim(claim)), Effect.andThen(effect)));
21
+ const expire = (op) => Effect.gen(function* () {
22
+ const loaded = yield* requireRun(op.runId);
23
+ const rows = yield* sql `
24
+ SELECT * FROM tenetkit_run_operations WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
25
+ `;
26
+ const row = rows[0];
27
+ if (row === undefined)
28
+ return yield* RuntimeUnavailable.make({ message: "operation missing" });
29
+ if (row.status !== "running") {
30
+ return { record: toOperationRecord(row), outcome: row.status };
31
+ }
32
+ if (canBlindRetry(row.replay_policy)) {
33
+ yield* sql `
34
+ UPDATE tenetkit_run_operations
35
+ SET status = 'requested', started_at = NULL, finished_at = NULL, owner_worker_id = NULL, lease_expires_at = NULL
36
+ WHERE run_id = ${op.runId} AND operation_id = ${op.operationId} AND status = 'running'
37
+ `;
38
+ const next = yield* sql `
39
+ SELECT * FROM tenetkit_run_operations WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
40
+ `;
41
+ return { record: toOperationRecord(next[0]), outcome: "retried" };
42
+ }
43
+ yield* sql `
44
+ UPDATE tenetkit_run_operations SET status = 'unknown', finished_at = NOW()
45
+ WHERE run_id = ${op.runId} AND operation_id = ${op.operationId} AND status = 'running'
46
+ `;
47
+ yield* appendEvent(hub, loaded, { _tag: "OperationUnknown", operationId: op.operationId }, loaded.cancellationRequested ? "cancelling" : "needs-resolution");
48
+ const next = yield* sql `
49
+ SELECT * FROM tenetkit_run_operations WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
50
+ `;
51
+ return { record: toOperationRecord(next[0]), outcome: "unknown" };
52
+ });
21
53
  return {
22
54
  recordOperation: (op) => fenced(op, Effect.gen(function* () {
23
55
  const loaded = yield* requireRun(op.runId);
@@ -212,37 +244,18 @@ export const postgresOperations = (input) => {
212
244
  return toOperationRecord(rows[0]);
213
245
  })),
214
246
  ...postgresModelResponseOperations(input),
215
- expireRunningOperation: (op) => fenced(op, Effect.gen(function* () {
216
- const loaded = yield* requireRun(op.runId);
217
- const rows = yield* sql `
218
- SELECT * FROM tenetkit_run_operations WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
247
+ expireRunningOperation: (op) => fenced(op, expire(op)),
248
+ recoverRunningOperations: (claim) => fenced(claim, Effect.gen(function* () {
249
+ const operations = yield* sql `
250
+ SELECT operation_id FROM tenetkit_run_operations
251
+ WHERE run_id = ${claim.runId} AND status = 'running'
252
+ ORDER BY operation_id
219
253
  `;
220
- const row = rows[0];
221
- if (row === undefined)
222
- return yield* RuntimeUnavailable.make({ message: "operation missing" });
223
- if (row.status !== "running") {
224
- return { record: toOperationRecord(row), outcome: row.status };
254
+ for (const operation of operations) {
255
+ yield* expire({ runId: claim.runId, operationId: operation.operation_id });
225
256
  }
226
- if (canBlindRetry(row.replay_policy)) {
227
- yield* sql `
228
- UPDATE tenetkit_run_operations
229
- SET status = 'requested', started_at = NULL, finished_at = NULL, owner_worker_id = NULL, lease_expires_at = NULL
230
- WHERE run_id = ${op.runId} AND operation_id = ${op.operationId} AND status = 'running'
231
- `;
232
- const next = yield* sql `
233
- SELECT * FROM tenetkit_run_operations WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
234
- `;
235
- return { record: toOperationRecord(next[0]), outcome: "retried" };
236
- }
237
- yield* sql `
238
- UPDATE tenetkit_run_operations SET status = 'unknown', finished_at = NOW()
239
- WHERE run_id = ${op.runId} AND operation_id = ${op.operationId} AND status = 'running'
240
- `;
241
- yield* appendEvent(hub, loaded, { _tag: "OperationUnknown", operationId: op.operationId }, loaded.cancellationRequested ? "cancelling" : "needs-resolution");
242
- const next = yield* sql `
243
- SELECT * FROM tenetkit_run_operations WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
244
- `;
245
- return { record: toOperationRecord(next[0]), outcome: "unknown" };
257
+ const loaded = yield* requireRun(claim.runId);
258
+ return loaded.status === "needs-resolution" ? "blocked" : "ready";
246
259
  })),
247
260
  getOperation: (op) => runNoTxn(Effect.gen(function* () {
248
261
  yield* requireRun(op.runId);
@@ -318,8 +331,15 @@ export const postgresOperations = (input) => {
318
331
  WHERE run_id = ${op.runId} AND operation_id = ${op.operationId} AND status = 'unknown'
319
332
  `;
320
333
  }
334
+ const unresolved = yield* sql `
335
+ SELECT COUNT(*)::int AS unresolved FROM tenetkit_run_operations
336
+ WHERE run_id = ${op.runId} AND status = 'unknown'
337
+ `;
338
+ const runStatus = Number(unresolved[0]?.unresolved ?? 0) > 0
339
+ ? sql `'needs-resolution'`
340
+ : sql `CASE WHEN cancellation_requested THEN 'cancelling' ELSE 'queued' END`;
321
341
  yield* sql `
322
- UPDATE tenetkit_runs SET status = CASE WHEN cancellation_requested THEN 'cancelling' ELSE 'queued' END, owner_worker_id = NULL, lease_expires_at = NULL, updated_at = NOW()
342
+ UPDATE tenetkit_runs SET status = ${runStatus}, owner_worker_id = NULL, lease_expires_at = NULL, updated_at = NOW()
323
343
  WHERE run_id = ${op.runId} AND status = 'needs-resolution'
324
344
  `;
325
345
  yield* settleAdmittedCancellation(hub, op.runId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "0.38.0",
3
+ "version": "0.38.2",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@effect/sql-pg": "4.0.0-rc.111",
42
- "tenetkit": "0.38.0"
42
+ "tenetkit": "0.38.2"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@effect/vitest": "4.0.0-rc.111",