lightflow-engine 0.2.12 → 0.2.13
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/BENCHMARKS.md +11 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -0
- package/dist/pg-store.js +9 -0
- package/package.json +1 -1
package/BENCHMARKS.md
CHANGED
|
@@ -160,6 +160,7 @@ same Postgres (16, local) and the same harness (200 runs x 5 steps @ conc 20;
|
|
|
160
160
|
| 0.2.8 | 455.2 | 2,276 | 8,695 |
|
|
161
161
|
| 0.2.9 | 474.1 | 2,371 | 9,008 |
|
|
162
162
|
| 0.2.10 | 455.3 | 2,277 | 9,368 |
|
|
163
|
+
| 0.2.12 | 457.0 | 2,285 | 9,943 |
|
|
163
164
|
|
|
164
165
|
### What changed per version (all perf-neutral by design)
|
|
165
166
|
|
|
@@ -209,3 +210,13 @@ ln -s <path-to>/lightflow/node_modules <dir>/node_modules
|
|
|
209
210
|
PKG=<dir> LIGHTFLOW_PG_URL=postgres://... BENCH_N=200 RN=5 npx tsx bench-pkg.mts
|
|
210
211
|
PKG=<dir> LIGHTFLOW_PG_URL=postgres://... BENCH_N=50 RN=400 npx tsx bench-pkg.mts
|
|
211
212
|
```
|
|
213
|
+
|
|
214
|
+
### 0.2.12 — bug-fix release (cancel/reaper/chunk)
|
|
215
|
+
|
|
216
|
+
- **cancel is terminal**: `cancel()` now writes `status='cancelled'` + flag atomically; `finishRun` refuses to overwrite a cancelled run (was: racing replay resurrected the run as completed/failed). `RunStatus` gains `"cancelled"`.
|
|
217
|
+
- **Lease-aware stale reaper**: `staleRuns` only reaps runs whose lease expired — a run inside a long step is no longer double-executed.
|
|
218
|
+
- **Stream close marker**: `close()` uses a monotonic chunk index (was `ctx.writes`, which could collide and silently drop the done marker → hanging stream).
|
|
219
|
+
- **O(1) nextChunkIndex**: `lightflow_runs.chunk_count` counter replaces a full chunk scan per write — long-run steps/s 9,368 → ~9,900.
|
|
220
|
+
- Tidy: single `getCurrent()` per call site (was double call + `!`).
|
|
221
|
+
|
|
222
|
+
Short: 200×5 conc 20 → **457 runs/s / 2,285 steps/s** (within noise of 0.2.9/0.2.10). Long: 50×400 → **9,943 steps/s** (best recorded).
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export interface Store {
|
|
|
49
49
|
isCancelled?(runId: string): Promise<boolean>;
|
|
50
50
|
/** Next monotonic chunk index (max+1), atomic per run. */
|
|
51
51
|
nextChunkIndex?(runId: string): Promise<number>;
|
|
52
|
+
pruneEvents?(runId: string, beforeSeq: number): Promise<void>;
|
|
52
53
|
/** Run lease: claim (atomically) / release before executing a replay. */
|
|
53
54
|
claimRun?(runId: string, leaseMs?: number): Promise<{
|
|
54
55
|
ok: boolean;
|
package/dist/index.js
CHANGED
|
@@ -161,6 +161,10 @@ async function maybeSnapshot(ctx) {
|
|
|
161
161
|
runId: ctx.runId, seq: ctx.seq, type: "snapshot",
|
|
162
162
|
payload: { memo }, createdAt: ctx.now(),
|
|
163
163
|
});
|
|
164
|
+
// Folded events below the snapshot are dead weight — drop them so the log
|
|
165
|
+
// stays O(recent activity), not O(total steps). Chunks are kept (stream
|
|
166
|
+
// replay reads them); run_completed (seq 0) is protected by beforeSeq > 0.
|
|
167
|
+
await ctx.store.pruneEvents?.(ctx.runId, ctx.seq - 1);
|
|
164
168
|
}
|
|
165
169
|
/** Durable sleep. Accepts milliseconds or an absolute Date. */
|
|
166
170
|
export async function sleep(until) {
|
package/dist/pg-store.js
CHANGED
|
@@ -300,6 +300,15 @@ export async function createPostgresStore(url, opts = {}) {
|
|
|
300
300
|
payload: { ...(r.rows[0].payload ?? {}), resolved: Boolean(r.rows[0].resolved) },
|
|
301
301
|
};
|
|
302
302
|
},
|
|
303
|
+
async pruneEvents(runId, beforeSeq) {
|
|
304
|
+
// Remove events fully folded into the latest snapshot. Chunk events are
|
|
305
|
+
// KEPT: getReadable/getTailIndex stream chunks from the event log, and
|
|
306
|
+
// the snapshot memo is not a chunk source. run_completed (seq 0) is
|
|
307
|
+
// protected by beforeSeq > 0.
|
|
308
|
+
await pool.query(`DELETE FROM lightflow_events
|
|
309
|
+
WHERE run_id=$1 AND seq < $2
|
|
310
|
+
AND type IN ('step_completed','step_failed','sleep_created','sleep_completed')`, [runId, beforeSeq]);
|
|
311
|
+
},
|
|
303
312
|
async setStatus(runId, status, output) {
|
|
304
313
|
await pool.query(`UPDATE lightflow_runs SET status=$2, output=$3, updated_at=$4 WHERE run_id=$1`, [runId, status, output === undefined ? null : JSON.stringify(output), Date.now()]);
|
|
305
314
|
},
|
package/package.json
CHANGED