@effect-agent/storage-sqlite 0.1.0-beta.42 → 0.1.0-beta.45
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/dist/index.mjs.map +1 -1
- package/dist/testing.mjs.map +1 -1
- package/package.json +1 -49
- package/src/errors.ts +1 -0
- package/src/sqlite-activity-store.ts +53 -0
- package/src/sqlite-journal.ts +52 -0
- package/src/sqlite-ledger.ts +307 -0
- package/src/sqlite-schedule-store.ts +39 -0
- package/src/sqlite-storage-failpoint-testing.ts +1 -0
- package/src/sqlite-subscription-store.ts +129 -0
- package/src/sqlite-thread-store.ts +74 -0
package/dist/testing.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.mjs","names":[],"sources":["../src/sqlite-storage-failpoint-testing.ts"],"sourcesContent":["import { Context, Effect, Layer, Ref } from \"effect\";\n\nimport {\n SqliteStorageFailpoint,\n type SqliteStorageFailpointHandler,\n} from \"./sqlite-storage-failpoint.ts\";\n\nconst noFailpoint: SqliteStorageFailpointHandler = () => Effect.void;\n\n/** Test-only control for replacing the active SQLite failpoint handler. */\nexport class SqliteStorageFailpointTestControl extends Context.Service<\n SqliteStorageFailpointTestControl,\n {\n readonly clear: Effect.Effect<void>;\n readonly setHandler: (handler: SqliteStorageFailpointHandler) => Effect.Effect<void>;\n }\n>()(\"@effect-agent/storage-sqlite/SqliteStorageFailpointTestControl\") {\n /** Reusable test Layer with a control service backed by the same handler Ref. */\n static readonly layer = Layer.effectContext(\n Effect.gen(function* () {\n const handler = yield* Ref.make<SqliteStorageFailpointHandler>(noFailpoint);\n return Context.make(\n SqliteStorageFailpoint,\n SqliteStorageFailpoint.of({\n hit: (location) => Ref.get(handler).pipe(Effect.flatMap((current) => current(location))),\n }),\n ).pipe(\n Context.add(\n SqliteStorageFailpointTestControl,\n SqliteStorageFailpointTestControl.of({\n clear: Ref.set(handler, noFailpoint),\n setHandler: (next) => Ref.set(handler, next),\n }),\n ),\n );\n }),\n );\n}\n"],"mappings":";;;AAOA,MAAM,oBAAmD,OAAO;;AAGhE,IAAa,oCAAb,MAAa,0CAA0C,QAAQ,QAM7D,CAAC,CAAC,gEAAgE,CAAC,CAAC;;CAEpE,OAAgB,QAAQ,MAAM,cAC5B,OAAO,IAAI,aAAa;EACtB,MAAM,UAAU,OAAO,IAAI,KAAoC,WAAW;
|
|
1
|
+
{"version":3,"file":"testing.mjs","names":[],"sources":["../src/sqlite-storage-failpoint-testing.ts"],"sourcesContent":["import { Context, Effect, Layer, Ref } from \"effect\";\n\nimport {\n SqliteStorageFailpoint,\n type SqliteStorageFailpointHandler,\n} from \"./sqlite-storage-failpoint.ts\";\n\nconst noFailpoint: SqliteStorageFailpointHandler = () => Effect.void;\n\n/** Test-only control for replacing the active SQLite failpoint handler. */\nexport class SqliteStorageFailpointTestControl extends Context.Service<\n SqliteStorageFailpointTestControl,\n {\n readonly clear: Effect.Effect<void>;\n readonly setHandler: (handler: SqliteStorageFailpointHandler) => Effect.Effect<void>;\n }\n>()(\"@effect-agent/storage-sqlite/SqliteStorageFailpointTestControl\") {\n /** Reusable test Layer with a control service backed by the same handler Ref. */\n static readonly layer = Layer.effectContext(\n Effect.gen(function* () {\n const handler = yield* Ref.make<SqliteStorageFailpointHandler>(noFailpoint);\n\n return Context.make(\n SqliteStorageFailpoint,\n SqliteStorageFailpoint.of({\n hit: (location) => Ref.get(handler).pipe(Effect.flatMap((current) => current(location))),\n }),\n ).pipe(\n Context.add(\n SqliteStorageFailpointTestControl,\n SqliteStorageFailpointTestControl.of({\n clear: Ref.set(handler, noFailpoint),\n setHandler: (next) => Ref.set(handler, next),\n }),\n ),\n );\n }),\n );\n}\n"],"mappings":";;;AAOA,MAAM,oBAAmD,OAAO;;AAGhE,IAAa,oCAAb,MAAa,0CAA0C,QAAQ,QAM7D,CAAC,CAAC,gEAAgE,CAAC,CAAC;;CAEpE,OAAgB,QAAQ,MAAM,cAC5B,OAAO,IAAI,aAAa;EACtB,MAAM,UAAU,OAAO,IAAI,KAAoC,WAAW;EAE1E,OAAO,QAAQ,KACb,wBACA,uBAAuB,GAAG,EACxB,MAAM,aAAa,IAAI,IAAI,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,YAAY,QAAQ,QAAQ,CAAC,CAAC,EACzF,CAAC,CACH,CAAC,CAAC,KACA,QAAQ,IACN,mCACA,kCAAkC,GAAG;GACnC,OAAO,IAAI,IAAI,SAAS,WAAW;GACnC,aAAa,SAAS,IAAI,IAAI,SAAS,IAAI;EAC7C,CAAC,CACH,CACF;CACF,CAAC,CACH;AACF"}
|
package/package.json
CHANGED
|
@@ -1,49 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@effect-agent/storage-sqlite",
|
|
3
|
-
"version": "0.1.0-beta.42",
|
|
4
|
-
"exports": {
|
|
5
|
-
".": {
|
|
6
|
-
"types": "./dist/index.d.mts",
|
|
7
|
-
"default": "./dist/index.mjs"
|
|
8
|
-
},
|
|
9
|
-
"./testing": {
|
|
10
|
-
"types": "./dist/testing.d.mts",
|
|
11
|
-
"default": "./dist/testing.mjs"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"dependencies": {
|
|
15
|
-
"@effect-agent/core": "0.1.0-beta.42",
|
|
16
|
-
"@effect-agent/thread": "0.1.0-beta.42",
|
|
17
|
-
"@effect/platform-node": "4.0.0-rc.111",
|
|
18
|
-
"@effect/sql-sqlite-node": "4.0.0-rc.111"
|
|
19
|
-
},
|
|
20
|
-
"peerDependencies": {
|
|
21
|
-
"effect": "^4.0.0-rc.111"
|
|
22
|
-
},
|
|
23
|
-
"description": "Node SQLite persistence adapters for the Effect Agent durable runtime and optional memory lifecycle.",
|
|
24
|
-
"license": "MIT",
|
|
25
|
-
"repository": {
|
|
26
|
-
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/danieljvdm/effect-agent.git",
|
|
28
|
-
"directory": "packages/storage-sqlite"
|
|
29
|
-
},
|
|
30
|
-
"files": [
|
|
31
|
-
"dist",
|
|
32
|
-
"src"
|
|
33
|
-
],
|
|
34
|
-
"type": "module",
|
|
35
|
-
"publishConfig": {
|
|
36
|
-
"access": "public"
|
|
37
|
-
},
|
|
38
|
-
"scripts": {
|
|
39
|
-
"build": "vp pack",
|
|
40
|
-
"check": "tsc --noEmit -p tsconfig.json",
|
|
41
|
-
"test": "vp test --passWithNoTests"
|
|
42
|
-
},
|
|
43
|
-
"devDependencies": {
|
|
44
|
-
"@effect/vitest": "4.0.0-rc.111",
|
|
45
|
-
"effect": "4.0.0-rc.111",
|
|
46
|
-
"typescript": "7.0.2",
|
|
47
|
-
"vite-plus": "0.3.0"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
1
|
+
{"name":"@effect-agent/storage-sqlite","version":"0.1.0-beta.45","dependencies":{"@effect-agent/core":"0.1.0-beta.45","@effect-agent/thread":"0.1.0-beta.45","@effect/platform-node":"4.0.0-rc.112","@effect/sql-sqlite-node":"4.0.0-rc.112"},"devDependencies":{"@effect/vitest":"4.0.0-rc.112","effect":"4.0.0-rc.112","typescript":"7.0.2","vite-plus":"0.3.0"},"peerDependencies":{"effect":"^4.0.0-rc.112"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./testing":{"types":"./dist/testing.d.mts","default":"./dist/testing.mjs"}},"description":"Node SQLite persistence adapters for the Effect Agent durable runtime and optional memory lifecycle.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/storage-sqlite"},"files":["dist","src"],"type":"module","publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
|
package/src/errors.ts
CHANGED
|
@@ -149,6 +149,7 @@ export const SqliteStorageFailpointLocation = Schema.Literals([
|
|
|
149
149
|
"ledger:child-settled:before",
|
|
150
150
|
"ledger:child-settled:after",
|
|
151
151
|
]);
|
|
152
|
+
|
|
152
153
|
export type SqliteStorageFailpointLocation = typeof SqliteStorageFailpointLocation.Type;
|
|
153
154
|
|
|
154
155
|
/** Deterministic test-only fault or pause injected at a SQLite operation boundary. */
|
|
@@ -111,14 +111,19 @@ const decodeProgress = Effect.fn("SqliteActivityStore.decodeProgress")(function*
|
|
|
111
111
|
const header = yield* Schema.decodeEffect(Schema.fromJsonString(StoredVersionHeader))(value).pipe(
|
|
112
112
|
Effect.mapError(() => storeError(operation, "corrupt")),
|
|
113
113
|
);
|
|
114
|
+
|
|
114
115
|
if (header.version !== STORAGE_VERSION) {
|
|
115
116
|
return yield* storeError(operation, "incompatible");
|
|
116
117
|
}
|
|
118
|
+
|
|
117
119
|
const progress = yield* Schema.decodeEffect(Schema.fromJsonString(ActivityProgress))(value).pipe(
|
|
118
120
|
Effect.mapError(() => storeError(operation, "corrupt")),
|
|
119
121
|
);
|
|
122
|
+
|
|
120
123
|
const canonical = yield* encodeProgress(progress, operation);
|
|
124
|
+
|
|
121
125
|
if (canonical !== value) return yield* storeError(operation, "corrupt");
|
|
126
|
+
|
|
122
127
|
return progress;
|
|
123
128
|
});
|
|
124
129
|
|
|
@@ -135,6 +140,7 @@ const validateProgress = Effect.fn("SqliteActivityStore.validateProgress")(funct
|
|
|
135
140
|
) {
|
|
136
141
|
return yield* storeError(operation, "corrupt");
|
|
137
142
|
}
|
|
143
|
+
|
|
138
144
|
return progress;
|
|
139
145
|
});
|
|
140
146
|
|
|
@@ -170,19 +176,23 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
170
176
|
version INTEGER NOT NULL
|
|
171
177
|
)
|
|
172
178
|
`;
|
|
179
|
+
|
|
173
180
|
const metadataRows = yield* sql<Record<string, unknown>>`
|
|
174
181
|
SELECT version FROM effect_agent_activity_metadata
|
|
175
182
|
WHERE component = ${METADATA_COMPONENT}
|
|
176
183
|
`;
|
|
184
|
+
|
|
177
185
|
const metadata = yield* decodeRows(
|
|
178
186
|
ActivityMetadataRow,
|
|
179
187
|
metadataRows,
|
|
180
188
|
"decode activity schema version",
|
|
181
189
|
);
|
|
190
|
+
|
|
182
191
|
if (metadata.length > 1) {
|
|
183
192
|
return yield* storeError("decode activity schema version", "corrupt");
|
|
184
193
|
}
|
|
185
194
|
const currentVersion = metadata[0]?.version;
|
|
195
|
+
|
|
186
196
|
if (currentVersion !== undefined && currentVersion !== STORAGE_VERSION) {
|
|
187
197
|
return yield* storeError("initialize activity schema", "incompatible");
|
|
188
198
|
}
|
|
@@ -191,11 +201,13 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
191
201
|
SELECT name FROM sqlite_master
|
|
192
202
|
WHERE type = 'table' AND name = ${STATE_TABLE}
|
|
193
203
|
`;
|
|
204
|
+
|
|
194
205
|
const existing = yield* decodeRows(
|
|
195
206
|
ActivityTableRow,
|
|
196
207
|
tableRows,
|
|
197
208
|
"inspect activity schema",
|
|
198
209
|
);
|
|
210
|
+
|
|
199
211
|
if (existing.length > 0) {
|
|
200
212
|
return yield* storeError("initialize activity schema", "incompatible");
|
|
201
213
|
}
|
|
@@ -244,14 +256,18 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
244
256
|
`,
|
|
245
257
|
operation,
|
|
246
258
|
);
|
|
259
|
+
|
|
247
260
|
const rows = yield* decodeRows(ActivityStateRow, rawRows, operation);
|
|
261
|
+
|
|
248
262
|
if (rows.length === 0) return null;
|
|
249
263
|
if (rows.length !== 1) return yield* storeError(operation, "corrupt");
|
|
250
264
|
const row = rows[0];
|
|
265
|
+
|
|
251
266
|
if (row.format_version !== STORAGE_VERSION) {
|
|
252
267
|
return yield* storeError(operation, "incompatible");
|
|
253
268
|
}
|
|
254
269
|
const progress = yield* decodeProgress(row.progress_json, operation);
|
|
270
|
+
|
|
255
271
|
yield* validateProgress(progress, operation);
|
|
256
272
|
if (
|
|
257
273
|
!sameKey(progress.key, key) ||
|
|
@@ -265,6 +281,7 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
265
281
|
) {
|
|
266
282
|
return yield* storeError(operation, "corrupt");
|
|
267
283
|
}
|
|
284
|
+
|
|
268
285
|
return progress;
|
|
269
286
|
});
|
|
270
287
|
|
|
@@ -275,7 +292,9 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
275
292
|
sql<Record<string, unknown>>`SELECT changes() AS changed`,
|
|
276
293
|
operation,
|
|
277
294
|
);
|
|
295
|
+
|
|
278
296
|
const rows = yield* decodeRows(ActivityChangeCountRow, rawRows, operation);
|
|
297
|
+
|
|
279
298
|
if (rows.length !== 1 || rows[0].changed !== 1) {
|
|
280
299
|
return yield* storeError(operation, "corrupt");
|
|
281
300
|
}
|
|
@@ -286,6 +305,7 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
286
305
|
operation: string,
|
|
287
306
|
) {
|
|
288
307
|
const progressJson = yield* encodeProgress(progress, operation);
|
|
308
|
+
|
|
289
309
|
yield* sql`
|
|
290
310
|
INSERT INTO effect_agent_activity_processor_state_v1 (
|
|
291
311
|
processor_id, processor_version, thread_id, format_version, through_sequence,
|
|
@@ -305,6 +325,7 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
305
325
|
operation: string,
|
|
306
326
|
) {
|
|
307
327
|
const progressJson = yield* encodeProgress(next, operation);
|
|
328
|
+
|
|
308
329
|
yield* sql`
|
|
309
330
|
UPDATE effect_agent_activity_processor_state_v1
|
|
310
331
|
SET format_version = ${STORAGE_VERSION},
|
|
@@ -328,6 +349,7 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
328
349
|
requireSequence: boolean,
|
|
329
350
|
): Effect.fn.Return<ActivityProgress, ActivityOwnershipLost> {
|
|
330
351
|
const now = yield* Clock.currentTimeMillis;
|
|
352
|
+
|
|
331
353
|
if (
|
|
332
354
|
progress === null ||
|
|
333
355
|
!sameKey(progress.key, claim.key) ||
|
|
@@ -338,6 +360,7 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
338
360
|
) {
|
|
339
361
|
return yield* ownershipLost(claim);
|
|
340
362
|
}
|
|
363
|
+
|
|
341
364
|
return progress;
|
|
342
365
|
});
|
|
343
366
|
|
|
@@ -345,6 +368,7 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
345
368
|
"SqliteActivityStore.inspect",
|
|
346
369
|
)(function* (key) {
|
|
347
370
|
const decodedKey = yield* decodeInput(ActivityProcessorKey, key, "inspect activity progress");
|
|
371
|
+
|
|
348
372
|
return yield* readProgress(decodedKey, "inspect activity progress");
|
|
349
373
|
});
|
|
350
374
|
|
|
@@ -352,18 +376,22 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
352
376
|
function* (request) {
|
|
353
377
|
const operation = "claim activity progress";
|
|
354
378
|
const decoded = yield* decodeInput(ActivityClaimRequest, request, operation);
|
|
379
|
+
|
|
355
380
|
yield* failpoint.hit("activity:claim:before");
|
|
381
|
+
|
|
356
382
|
const claimed = yield* sql
|
|
357
383
|
.withTransaction(
|
|
358
384
|
Effect.gen(function* () {
|
|
359
385
|
const current = yield* readProgress(decoded.key, operation);
|
|
360
386
|
const now = yield* Clock.currentTimeMillis;
|
|
387
|
+
|
|
361
388
|
if (current !== null && current.owner !== null && current.leaseExpiresAt > now) {
|
|
362
389
|
return yield* ActivityBusy.make({
|
|
363
390
|
key: decoded.key,
|
|
364
391
|
leaseExpiresAt: current.leaseExpiresAt,
|
|
365
392
|
});
|
|
366
393
|
}
|
|
394
|
+
|
|
367
395
|
const next = yield* Schema.decodeUnknownEffect(ActivityProgress)({
|
|
368
396
|
version: STORAGE_VERSION,
|
|
369
397
|
key: decoded.key,
|
|
@@ -374,16 +402,21 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
374
402
|
pending: current?.pending ?? null,
|
|
375
403
|
advancedAt: current?.advancedAt ?? null,
|
|
376
404
|
}).pipe(Effect.mapError(() => storeError(operation, "corrupt")));
|
|
405
|
+
|
|
377
406
|
if (current === null) yield* insertProgress(next, operation);
|
|
378
407
|
else yield* updateProgress(current, next, operation);
|
|
379
408
|
yield* failpoint.hit("activity:claim:after-state");
|
|
380
409
|
const result = makeClaim(next);
|
|
410
|
+
|
|
381
411
|
if (result === null) return yield* storeError(operation, "corrupt");
|
|
412
|
+
|
|
382
413
|
return result;
|
|
383
414
|
}),
|
|
384
415
|
)
|
|
385
416
|
.pipe(Effect.catchTag("SqlError", () => Effect.fail(storeError(operation))));
|
|
417
|
+
|
|
386
418
|
yield* failpoint.hit("activity:claim:after");
|
|
419
|
+
|
|
387
420
|
return claimed;
|
|
388
421
|
},
|
|
389
422
|
);
|
|
@@ -394,7 +427,9 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
394
427
|
const operation = "prepare activity output";
|
|
395
428
|
const claim = yield* decodeInput(ActivityClaim, request.claim, operation);
|
|
396
429
|
const work = yield* decodeInput(PreparedActivity, request.work, operation);
|
|
430
|
+
|
|
397
431
|
yield* failpoint.hit("activity:prepare:before");
|
|
432
|
+
|
|
398
433
|
const result = yield* sql
|
|
399
434
|
.withTransaction(
|
|
400
435
|
Effect.gen(function* () {
|
|
@@ -403,23 +438,29 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
403
438
|
claim,
|
|
404
439
|
true,
|
|
405
440
|
);
|
|
441
|
+
|
|
406
442
|
if (current.pending !== null) {
|
|
407
443
|
if (sameWork(current.pending, work)) {
|
|
408
444
|
return { work: current.pending, changed: false } as const;
|
|
409
445
|
}
|
|
446
|
+
|
|
410
447
|
return yield* ActivityWorkConflict.make({ key: claim.key, workId: work.workId });
|
|
411
448
|
}
|
|
412
449
|
if (!sameKey(work.key, claim.key) || work.sequence !== current.throughSequence + 1) {
|
|
413
450
|
return yield* ActivityWorkConflict.make({ key: claim.key, workId: work.workId });
|
|
414
451
|
}
|
|
415
452
|
const next = ActivityProgress.make({ ...current, pending: work });
|
|
453
|
+
|
|
416
454
|
yield* updateProgress(current, next, operation);
|
|
417
455
|
yield* failpoint.hit("activity:prepare:after-state");
|
|
456
|
+
|
|
418
457
|
return { work, changed: true } as const;
|
|
419
458
|
}),
|
|
420
459
|
)
|
|
421
460
|
.pipe(Effect.catchTag("SqlError", () => Effect.fail(storeError(operation))));
|
|
461
|
+
|
|
422
462
|
if (result.changed) yield* failpoint.hit("activity:prepare:after");
|
|
463
|
+
|
|
423
464
|
return result.work;
|
|
424
465
|
});
|
|
425
466
|
|
|
@@ -429,7 +470,9 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
429
470
|
const operation = "advance activity progress";
|
|
430
471
|
const claim = yield* decodeInput(ActivityClaim, request.claim, operation);
|
|
431
472
|
const workId = yield* decodeInput(Digest, request.workId, operation);
|
|
473
|
+
|
|
432
474
|
yield* failpoint.hit("activity:advance:before");
|
|
475
|
+
|
|
433
476
|
const nextClaim = yield* sql
|
|
434
477
|
.withTransaction(
|
|
435
478
|
Effect.gen(function* () {
|
|
@@ -438,24 +481,31 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
438
481
|
claim,
|
|
439
482
|
true,
|
|
440
483
|
);
|
|
484
|
+
|
|
441
485
|
if (current.pending === null || current.pending.workId !== workId) {
|
|
442
486
|
return yield* ActivityWorkConflict.make({ key: claim.key, workId });
|
|
443
487
|
}
|
|
488
|
+
|
|
444
489
|
const next = ActivityProgress.make({
|
|
445
490
|
...current,
|
|
446
491
|
throughSequence: current.pending.sequence,
|
|
447
492
|
pending: null,
|
|
448
493
|
advancedAt: yield* Clock.currentTimeMillis,
|
|
449
494
|
});
|
|
495
|
+
|
|
450
496
|
yield* updateProgress(current, next, operation);
|
|
451
497
|
yield* failpoint.hit("activity:advance:after-state");
|
|
452
498
|
const result = makeClaim(next);
|
|
499
|
+
|
|
453
500
|
if (result === null) return yield* storeError(operation, "corrupt");
|
|
501
|
+
|
|
454
502
|
return result;
|
|
455
503
|
}),
|
|
456
504
|
)
|
|
457
505
|
.pipe(Effect.catchTag("SqlError", () => Effect.fail(storeError(operation))));
|
|
506
|
+
|
|
458
507
|
yield* failpoint.hit("activity:advance:after");
|
|
508
|
+
|
|
459
509
|
return nextClaim;
|
|
460
510
|
});
|
|
461
511
|
|
|
@@ -464,11 +514,13 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
464
514
|
)(function* (claim) {
|
|
465
515
|
const operation = "release activity claim";
|
|
466
516
|
const decoded = yield* decodeInput(ActivityClaim, claim, operation);
|
|
517
|
+
|
|
467
518
|
yield* failpoint.hit("activity:release:before");
|
|
468
519
|
yield* sql
|
|
469
520
|
.withTransaction(
|
|
470
521
|
Effect.gen(function* () {
|
|
471
522
|
const current = yield* readProgress(decoded.key, operation);
|
|
523
|
+
|
|
472
524
|
if (
|
|
473
525
|
current === null ||
|
|
474
526
|
current.owner !== decoded.owner ||
|
|
@@ -477,6 +529,7 @@ const makeActivityStore = Effect.fn("SqliteActivityStore.make")(function* () {
|
|
|
477
529
|
return yield* ownershipLost(decoded);
|
|
478
530
|
}
|
|
479
531
|
const next = ActivityProgress.make({ ...current, owner: null, leaseExpiresAt: 0 });
|
|
532
|
+
|
|
480
533
|
yield* updateProgress(current, next, operation);
|
|
481
534
|
yield* failpoint.hit("activity:release:after-state");
|
|
482
535
|
}),
|