This commit is contained in:
2026-08-04 10:26:54 -05:00
parent 96a37a495e
commit da3f8434a1
11 changed files with 926 additions and 77 deletions

View File

@@ -14,7 +14,13 @@ import { query, queryOne } from './db.js';
export interface TaskKeys {
/** idle | running | error:<message> */
state: string;
/** ISO timestamp of the last completed run. */
/**
* ISO timestamp of the last completed run — written by the **job**, never
* by this module. Each job owns its own key and the two sets are disjoint
* (`ds_*_refresh_*` vs `ds_*_sync_*`), because `ds_last_refresh_at` is not
* merely a display value: it is the boundary the sync uses to decide what
* the refresh can no longer reach. See startTask().
*/
lastAt: string;
/** JSON result of the last completed run. */
lastResult: string;
@@ -71,6 +77,13 @@ export async function clearStaleTask(
/**
* Claims the slot and runs `job` detached. `false` means somebody else is
* already running it — the caller answers 409.
*
* It deliberately does **not** stamp `keys.lastAt`. A shared helper writing
* "this ran at" on every resolved job is how `ds_last_refresh_at` came to move
* forward on runs that had walked nothing: the refresh cursor then pointed
* past requests that were never mirrored, and nothing downstream could tell
* the difference. Each job writes its own `lastAt` at the point where it knows
* its work is done and stored.
*/
export async function startTask<T>(
keys: TaskKeys,
@@ -84,7 +97,6 @@ export async function startTask<T>(
try {
const result = await job();
await setMeta(keys.lastResult, JSON.stringify(result));
await setMeta(keys.lastAt, new Date().toISOString());
await setMeta(keys.state, 'idle');
} catch (err) {
const message = (err as Error).message;