cairnq 0.15.0 → 0.15.1

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/worker.d.ts CHANGED
@@ -87,6 +87,8 @@ export declare class Worker {
87
87
  private readonly backoffMaxMs;
88
88
  private stopped;
89
89
  private stopWake;
90
+ private freed$;
91
+ private freedWake;
90
92
  private readonly stopped$;
91
93
  private ownsStore;
92
94
  constructor(store: TaskStore, queues: string[], opts?: WorkerOptions);
@@ -279,6 +281,9 @@ export declare class Worker {
279
281
  * cuts it short when a task on this worker's queues becomes claimable;
280
282
  * stop() interrupts it either way, and sleepOrStop bounds it at `ms` so the
281
283
  * poll fallback — which also drives lease recovery — never stretches.
284
+ *
285
+ * `freed` is the third way out: a resource unit coming back frees a claim the
286
+ * store has no reason to announce (see `freed$`).
282
287
  */
283
288
  private idle;
284
289
  private sleepOrStop;
package/dist/worker.js CHANGED
@@ -162,6 +162,13 @@ export class Worker {
162
162
  backoffMaxMs;
163
163
  stopped = false;
164
164
  stopWake;
165
+ // Re-armed before each claim, resolved when a call gives a resource unit
166
+ // back. A claim can come back empty because a resource is at capacity rather
167
+ // than the queue, and that release is local — no store notification covers
168
+ // it, so the idle sleep waits on this too. Armed before the claim, so a
169
+ // release landing *during* it still shortens the sleep that follows.
170
+ freed$ = Promise.resolve();
171
+ freedWake = () => { };
165
172
  // Resolved once by stop(); every sleep races against it. A stopped worker
166
173
  // never restarts, so one promise serves the instance's lifetime.
167
174
  stopped$ = new Promise((r) => (this.stopWake = r));
@@ -353,6 +360,7 @@ export class Worker {
353
360
  await this.idle(pollMs);
354
361
  continue;
355
362
  }
363
+ this.freed$ = new Promise((r) => (this.freedWake = r));
356
364
  let drawn;
357
365
  try {
358
366
  drawn = await this.store.claimSession(
@@ -369,7 +377,7 @@ export class Worker {
369
377
  continue;
370
378
  }
371
379
  if (!drawn?.length) {
372
- await this.idle(pollMs);
380
+ await this.idle(pollMs, this.freed$);
373
381
  continue;
374
382
  }
375
383
  for (const { src, calls } of drawn) {
@@ -384,6 +392,8 @@ export class Worker {
384
392
  const p = call.finally(() => {
385
393
  this.planner.release(resource);
386
394
  running.delete(p);
395
+ if (resource != null)
396
+ this.freedWake();
387
397
  });
388
398
  running.add(p);
389
399
  }
@@ -746,9 +756,15 @@ export class Worker {
746
756
  * cuts it short when a task on this worker's queues becomes claimable;
747
757
  * stop() interrupts it either way, and sleepOrStop bounds it at `ms` so the
748
758
  * poll fallback — which also drives lease recovery — never stretches.
759
+ *
760
+ * `freed` is the third way out: a resource unit coming back frees a claim the
761
+ * store has no reason to announce (see `freed$`).
749
762
  */
750
- idle(ms) {
751
- return Promise.race([this.sleepOrStop(ms), this.store.claimWake(this.queues, ms)]);
763
+ idle(ms, freed) {
764
+ const racers = [this.sleepOrStop(ms), this.store.claimWake(this.queues, ms)];
765
+ if (freed)
766
+ racers.push(freed);
767
+ return Promise.race(racers);
752
768
  }
753
769
  sleepOrStop(ms) {
754
770
  if (this.stopped)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cairnq",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "description": "SQLite-first, cross-language, storage-centered durable task runtime",
5
5
  "license": "MIT",
6
6
  "author": "Jannchie <jannchie@gmail.com>",
package/src/worker.ts CHANGED
@@ -281,6 +281,13 @@ export class Worker {
281
281
  private readonly backoffMaxMs: number;
282
282
  private stopped = false;
283
283
  private stopWake!: () => void;
284
+ // Re-armed before each claim, resolved when a call gives a resource unit
285
+ // back. A claim can come back empty because a resource is at capacity rather
286
+ // than the queue, and that release is local — no store notification covers
287
+ // it, so the idle sleep waits on this too. Armed before the claim, so a
288
+ // release landing *during* it still shortens the sleep that follows.
289
+ private freed$ = Promise.resolve();
290
+ private freedWake: () => void = () => {};
284
291
  // Resolved once by stop(); every sleep races against it. A stopped worker
285
292
  // never restarts, so one promise serves the instance's lifetime.
286
293
  private readonly stopped$ = new Promise<void>((r) => (this.stopWake = r));
@@ -519,6 +526,7 @@ export class Worker {
519
526
  await this.idle(pollMs);
520
527
  continue;
521
528
  }
529
+ this.freed$ = new Promise<void>((r) => (this.freedWake = r));
522
530
  let drawn: Draw[] | undefined;
523
531
  try {
524
532
  drawn = await this.store.claimSession(
@@ -536,7 +544,7 @@ export class Worker {
536
544
  continue;
537
545
  }
538
546
  if (!drawn?.length) {
539
- await this.idle(pollMs);
547
+ await this.idle(pollMs, this.freed$);
540
548
  continue;
541
549
  }
542
550
  for (const { src, calls } of drawn) {
@@ -552,6 +560,7 @@ export class Worker {
552
560
  const p = call.finally(() => {
553
561
  this.planner.release(resource);
554
562
  running.delete(p);
563
+ if (resource != null) this.freedWake();
555
564
  });
556
565
  running.add(p);
557
566
  }
@@ -929,9 +938,14 @@ export class Worker {
929
938
  * cuts it short when a task on this worker's queues becomes claimable;
930
939
  * stop() interrupts it either way, and sleepOrStop bounds it at `ms` so the
931
940
  * poll fallback — which also drives lease recovery — never stretches.
941
+ *
942
+ * `freed` is the third way out: a resource unit coming back frees a claim the
943
+ * store has no reason to announce (see `freed$`).
932
944
  */
933
- private idle(ms: number): Promise<void> {
934
- return Promise.race([this.sleepOrStop(ms), this.store.claimWake(this.queues, ms)]);
945
+ private idle(ms: number, freed?: Promise<void>): Promise<void> {
946
+ const racers = [this.sleepOrStop(ms), this.store.claimWake(this.queues, ms)];
947
+ if (freed) racers.push(freed);
948
+ return Promise.race(racers);
935
949
  }
936
950
 
937
951
  private sleepOrStop(ms: number): Promise<void> {