@ultimat3/jobs 29.3.1 → 29.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.
Files changed (2) hide show
  1. package/package.json +6 -6
  2. package/src/leases.ts +22 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/jobs",
3
- "version": "29.3.1",
3
+ "version": "29.4.0",
4
4
  "description": "Durable background work: steps, transactional outbox, cron tasks, one driver interface",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,10 +33,10 @@
33
33
  "test": "bun test"
34
34
  },
35
35
  "dependencies": {
36
- "@ultimat3/core": "29.3.1",
37
- "@ultimat3/db": "29.3.1",
38
- "@ultimat3/entity": "29.3.1",
39
- "@ultimat3/schema": "29.3.1",
40
- "@ultimat3/time": "29.3.1"
36
+ "@ultimat3/core": "29.4.0",
37
+ "@ultimat3/db": "29.4.0",
38
+ "@ultimat3/entity": "29.4.0",
39
+ "@ultimat3/schema": "29.4.0",
40
+ "@ultimat3/time": "29.4.0"
41
41
  }
42
42
  }
package/src/leases.ts CHANGED
@@ -50,8 +50,13 @@ export interface MemoryLeaseStoreOptions {
50
50
  export interface MemoryLeaseStore extends LeaseStore {
51
51
  /** Keys with at least one live slot. A key nothing holds is not retained — see `live`. */
52
52
  tracked(): number;
53
+ /** Keys in the heap right now, expired or not — no sweep. What the sweep's own test reads. */
54
+ retained(): number;
53
55
  }
54
56
 
57
+ /** How often `acquire` sweeps every key for expired slots: at most once per this many ms. */
58
+ export const LEASE_SWEEP_INTERVAL_MS = 60_000;
59
+
55
60
  /**
56
61
  * The `x dev` / test implementation. One heap, so it is not a fleet gate — it exists so the
57
62
  * memory driver enforces `concurrency` with the same code path the pg driver does, and so the
@@ -75,8 +80,22 @@ export function memoryLeaseStore(options: MemoryLeaseStoreOptions = {}): MemoryL
75
80
  return held;
76
81
  };
77
82
 
83
+ /**
84
+ * `live` only prunes the key it is asked about, so a key acquired once and never asked about
85
+ * again (its job's run crashed before release, one key per account) kept its expired slot for
86
+ * the life of the process. Bounded to once a minute: a sweep walks every key.
87
+ */
88
+ let swept = nowMs(clock);
89
+ const sweep = (): void => {
90
+ const at = nowMs(clock);
91
+ if (at - swept < LEASE_SWEEP_INTERVAL_MS) return;
92
+ swept = at;
93
+ for (const key of [...slots.keys()]) live(key);
94
+ };
95
+
78
96
  return {
79
97
  acquire(key, limit, ttlMs, holder) {
98
+ sweep();
80
99
  const held = live(key);
81
100
  for (let slot = 0; slot < limit; slot += 1) {
82
101
  if (held.has(slot)) continue;
@@ -114,6 +133,9 @@ export function memoryLeaseStore(options: MemoryLeaseStoreOptions = {}): MemoryL
114
133
  for (const key of [...slots.keys()]) live(key);
115
134
  return slots.size;
116
135
  },
136
+ retained() {
137
+ return slots.size;
138
+ },
117
139
  };
118
140
  }
119
141