@bitclaw/jobs 1.2.0 → 1.3.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.
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { JobQueue } from './queue';
4
4
  export { SlidingWindowRateLimiter } from './rate-limiter';
5
5
  export { Scheduler } from './scheduler';
6
6
  export { applyPragmas, initializeSchema } from './schema';
7
- export type { AddJobOptions, AddScheduleOptions, BatchOptions, FailedJob, Job, JobBatch, JobContext, JobMap, JobStats, JobStatus, ListJobsOptions, PaginatedResult, PurgeOptions, RateLimit, Schedule, WorkerOptions } from './types';
7
+ export type { AddJobOptions, AddScheduleOptions, BackoffConfig, BatchOptions, FailedJob, Job, JobBatch, JobContext, JobMap, JobStats, JobStatus, ListJobsOptions, PaginatedResult, PurgeOptions, RateLimit, Schedule, WorkerOptions } from './types';
8
8
  export { NonRetryableError } from './types';
9
9
  export { JobWorker } from './worker';
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC1D,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,GAAG,EACH,QAAQ,EACR,UAAU,EACV,MAAM,EACN,QAAQ,EACR,SAAS,EACT,eAAe,EACf,eAAe,EACf,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,aAAa,EACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC1D,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,SAAS,EACT,GAAG,EACH,QAAQ,EACR,UAAU,EACV,MAAM,EACN,QAAQ,EACR,SAAS,EACT,eAAe,EACf,eAAe,EACf,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,aAAa,EACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
package/dist/queue.d.ts CHANGED
@@ -57,6 +57,18 @@ export declare class JobQueue<TMap extends JobMap = Record<string, unknown>> {
57
57
  type: K;
58
58
  }): JobWorker<TMap, K>;
59
59
  private insertJob;
60
+ /**
61
+ * Reset stuck `processing` jobs back to `pending`. Call at startup to recover
62
+ * from server crashes that left jobs claimed but never completed.
63
+ * @param thresholdMs Jobs processing longer than this (ms) are reset. Default 5min.
64
+ * @returns Number of jobs reset.
65
+ */
66
+ reconcileStaleJobs(thresholdMs?: number): number;
67
+ /**
68
+ * Look up a pending or processing job by its uniqueKey.
69
+ * Returns null if no such job exists (completed, dead-lettered, or never queued).
70
+ */
71
+ getJobByUniqueKey(type: string, uniqueKey: string): Job | null;
60
72
  close(): void;
61
73
  private unblockDependents;
62
74
  private handleBatchJobComplete;
@@ -1 +1 @@
1
- {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,OAAO,KAAK,EACV,aAAa,EAEb,YAAY,EACZ,SAAS,EAET,GAAG,EACH,QAAQ,EAER,MAAM,EAEN,QAAQ,EACR,eAAe,EACf,eAAe,EACf,YAAY,EAEZ,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAuDrC,qBAAa,QAAQ,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACjE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IAEtB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IACnC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAGrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC;IAC3C,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;gBAEzB,MAAM,EAAE,MAAM;IAuG1B,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,EAC/B,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EACb,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM;IAIT,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAK9B,QAAQ,IAAI,QAAQ;IAwBpB,aAAa,CAAC,OAAO,CAAC,EAAE;QACtB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,eAAe,CAAC,SAAS,CAAC;IAkC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,eAAe,CAAC,GAAG,CAAC;IAkCzD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAS9B,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IASlC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAQxE,WAAW,IAAI,MAAM,EAAE;IAOvB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IA+B3C,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAQ5C,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM;IAQpC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAgBtC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAa7B,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IA4B5C,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAkD9C,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAUlD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM;IAWzD,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,EACtC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EACb,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM;IAYT,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAO1C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAMlC,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,EACxC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,GAC5C,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IAIrB,OAAO,CAAC,SAAS;IAmDjB;;;;;OAKG;IACH,kBAAkB,CAAC,WAAW,SAAU,GAAG,MAAM;IAcjD;;;OAGG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAY9D,KAAK,IAAI,IAAI;IAWb,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,sBAAsB;CAgD/B"}
package/dist/queue.js CHANGED
@@ -89,8 +89,8 @@ export class JobQueue {
89
89
  applyPragmas(this.db);
90
90
  initializeSchema(this.db);
91
91
  this.insertJobStmt = this.db.query(`
92
- INSERT OR IGNORE INTO jobs (type, data, status, priority, max_retries, run_at, batch_id, unique_key)
93
- VALUES ($type, $data, $status, $priority, $maxRetries, $runAt, $batchId, $uniqueKey)
92
+ INSERT OR IGNORE INTO jobs (type, data, status, priority, max_retries, run_at, batch_id, unique_key, backoff_config)
93
+ VALUES ($type, $data, $status, $priority, $maxRetries, $runAt, $batchId, $uniqueKey, $backoffConfig)
94
94
  `);
95
95
  this.selectDedupedJobStmt = this.db.query(`
96
96
  SELECT id FROM jobs
@@ -121,6 +121,7 @@ export class JobQueue {
121
121
  SET status = 'pending',
122
122
  retry_count = retry_count + 1,
123
123
  error = $error,
124
+ run_at = $runAt,
124
125
  updated_at = $now
125
126
  WHERE id = $id
126
127
  `);
@@ -287,7 +288,8 @@ export class JobQueue {
287
288
  $maxRetries: row.max_retries,
288
289
  $runAt: now,
289
290
  $batchId: null,
290
- $uniqueKey: null
291
+ $uniqueKey: null,
292
+ $backoffConfig: null
291
293
  });
292
294
  const newJobId = this.lastInsertRowIdStmt.get();
293
295
  this.db
@@ -390,7 +392,22 @@ export class JobQueue {
390
392
  }
391
393
  }
392
394
  else {
393
- this.markFailedStmt.run({ $id: id, $error: error, $now: now });
395
+ const backoff = row.backoff_config
396
+ ? JSON.parse(row.backoff_config)
397
+ : null;
398
+ let retryRunAt = now;
399
+ if (backoff) {
400
+ const delayMs = backoff.type === 'exponential'
401
+ ? Math.min(backoff.delayMs * 2 ** row.retry_count, 3_600_000)
402
+ : backoff.delayMs;
403
+ retryRunAt = new Date(Date.now() + delayMs).toISOString();
404
+ }
405
+ this.markFailedStmt.run({
406
+ $id: id,
407
+ $error: error,
408
+ $runAt: retryRunAt,
409
+ $now: now
410
+ });
394
411
  }
395
412
  })();
396
413
  }
@@ -446,7 +463,8 @@ export class JobQueue {
446
463
  $maxRetries: options?.maxRetries ?? 3,
447
464
  $runAt: runAt,
448
465
  $batchId: batchId,
449
- $uniqueKey: options?.uniqueKey ?? null
466
+ $uniqueKey: options?.uniqueKey ?? null,
467
+ $backoffConfig: options?.backoff ? JSON.stringify(options.backoff) : null
450
468
  });
451
469
  // INSERT OR IGNORE: if a pending/processing job with same (type, uniqueKey)
452
470
  // already exists, the insert is a no-op. Return the existing job id.
@@ -472,6 +490,36 @@ export class JobQueue {
472
490
  }
473
491
  return jobId.id;
474
492
  }
493
+ /**
494
+ * Reset stuck `processing` jobs back to `pending`. Call at startup to recover
495
+ * from server crashes that left jobs claimed but never completed.
496
+ * @param thresholdMs Jobs processing longer than this (ms) are reset. Default 5min.
497
+ * @returns Number of jobs reset.
498
+ */
499
+ reconcileStaleJobs(thresholdMs = 300_000) {
500
+ const cutoff = new Date(Date.now() - thresholdMs).toISOString();
501
+ const result = this.db
502
+ .query(`UPDATE jobs
503
+ SET status = 'pending',
504
+ error = 'stale: worker crash or restart — reset for retry',
505
+ updated_at = $now
506
+ WHERE status = 'processing' AND updated_at < $cutoff`)
507
+ .run({ $now: nowISO(), $cutoff: cutoff });
508
+ return result.changes;
509
+ }
510
+ /**
511
+ * Look up a pending or processing job by its uniqueKey.
512
+ * Returns null if no such job exists (completed, dead-lettered, or never queued).
513
+ */
514
+ getJobByUniqueKey(type, uniqueKey) {
515
+ const row = this.db
516
+ .query(`SELECT * FROM jobs
517
+ WHERE type = $type AND unique_key = $uniqueKey
518
+ AND status IN ('pending', 'processing')
519
+ LIMIT 1`)
520
+ .get({ $type: type, $uniqueKey: uniqueKey });
521
+ return row ? toJob(row) : null;
522
+ }
475
523
  close() {
476
524
  try {
477
525
  if (this.db.filename !== ':memory:' && this.db.filename !== '') {
@@ -522,7 +570,8 @@ export class JobQueue {
522
570
  $maxRetries: 3,
523
571
  $runAt: now,
524
572
  $batchId: null,
525
- $uniqueKey: null
573
+ $uniqueKey: null,
574
+ $backoffConfig: null
526
575
  });
527
576
  }
528
577
  // Enqueue "finally" callback job regardless of failures
@@ -535,7 +584,8 @@ export class JobQueue {
535
584
  $maxRetries: 3,
536
585
  $runAt: now,
537
586
  $batchId: null,
538
- $uniqueKey: null
587
+ $uniqueKey: null,
588
+ $backoffConfig: null
539
589
  });
540
590
  }
541
591
  }
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmG3C,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAY/C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAmBnD"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAoG3C,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAY/C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAsBnD"}
package/dist/schema.js CHANGED
@@ -17,7 +17,8 @@ CREATE TABLE IF NOT EXISTS jobs (
17
17
  request_log TEXT,
18
18
  response_log TEXT,
19
19
  batch_id TEXT REFERENCES job_batches(id),
20
- unique_key TEXT
20
+ unique_key TEXT,
21
+ backoff_config TEXT
21
22
  )`;
22
23
  // State-aware dedup: same (type, unique_key) cannot be both pending/processing at once.
23
24
  // Once the job completes, the same key can be re-enqueued.
@@ -107,12 +108,13 @@ export function initializeSchema(db) {
107
108
  db.run(FAILED_JOBS_TABLE);
108
109
  db.run(SCHEDULES_TABLE);
109
110
  db.run(SCHEDULES_NEXT_RUN_INDEX);
110
- // Migration: add unique_key to existing DBs that were created before v1.2.0
111
- const cols = db
112
- .prepare("PRAGMA table_info(jobs)")
113
- .all();
111
+ // Migrations for columns added after initial schema creation
112
+ const cols = db.prepare('PRAGMA table_info(jobs)').all();
114
113
  if (!cols.some(c => c.name === 'unique_key')) {
115
114
  db.run('ALTER TABLE jobs ADD COLUMN unique_key TEXT');
116
115
  }
116
+ if (!cols.some(c => c.name === 'backoff_config')) {
117
+ db.run('ALTER TABLE jobs ADD COLUMN backoff_config TEXT');
118
+ }
117
119
  db.run(JOBS_UNIQUE_KEY_INDEX);
118
120
  }
package/dist/types.d.ts CHANGED
@@ -41,6 +41,11 @@ export type FailedJob = {
41
41
  readonly requestLog: string | null;
42
42
  readonly responseLog: string | null;
43
43
  };
44
+ export type BackoffConfig = {
45
+ type: 'exponential' | 'fixed';
46
+ /** Base delay in ms. Exponential: delayMs * 2^retryCount. Fixed: always delayMs. Max 1h. */
47
+ delayMs: number;
48
+ };
44
49
  export type AddJobOptions = {
45
50
  priority?: number;
46
51
  runAt?: Date;
@@ -52,6 +57,11 @@ export type AddJobOptions = {
52
57
  * existing job id is returned. Once the job completes, the same key can be re-used.
53
58
  */
54
59
  uniqueKey?: string;
60
+ /**
61
+ * Backoff strategy for retries. Exponential: delayMs * 2^retryCount, capped at 1h.
62
+ * Fixed: always delayMs between retries. Default: retry immediately.
63
+ */
64
+ backoff?: BackoffConfig;
55
65
  };
56
66
  export type JobContext = {
57
67
  reportProgress: (percent: number) => void;
@@ -69,6 +79,8 @@ export type WorkerOptions<T = unknown> = {
69
79
  onError?: (job: Job<T>, error: unknown) => void;
70
80
  /** Hard wall-clock limit per job execution in ms. Job is marked failed on timeout. */
71
81
  timeoutMs?: number;
82
+ /** Max concurrent jobs this worker runs simultaneously. Default: 1. */
83
+ concurrency?: number;
72
84
  };
73
85
  export type JobStats = {
74
86
  pending: number;
@@ -113,6 +125,7 @@ export type JobRow = {
113
125
  request_log: string | null;
114
126
  response_log: string | null;
115
127
  unique_key: string | null;
128
+ backoff_config: string | null;
116
129
  };
117
130
  export type FailedJobRow = {
118
131
  id: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/worker.d.ts CHANGED
@@ -7,7 +7,7 @@ export declare class JobWorker<TMap extends JobMap = Record<string, unknown>, K
7
7
  private abortController;
8
8
  private timer;
9
9
  private running;
10
- private processing;
10
+ private activeCount;
11
11
  private stopResolve;
12
12
  constructor(queue: JobQueue<TMap>, options: WorkerOptions<TMap[K]> & {
13
13
  type: K;
@@ -17,5 +17,6 @@ export declare class JobWorker<TMap extends JobMap = Record<string, unknown>, K
17
17
  stop(): Promise<void>;
18
18
  private scheduleNext;
19
19
  private poll;
20
+ private runJob;
20
21
  }
21
22
  //# sourceMappingURL=worker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,KAAK,EAAmB,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGtE,qBAAa,SAAS,CACpB,IAAI,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,GAAG,MAAM,GAAG,MAAM,IAAI;IAEnD,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAA6B;gBAG9C,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EACrB,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE;IAY/C,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,KAAK,IAAI,IAAI;IAOP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B,OAAO,CAAC,YAAY;YAMN,IAAI;CAqEnB"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,KAAK,EAAmB,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGtE,qBAAa,SAAS,CACpB,IAAI,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,GAAG,MAAM,GAAG,MAAM,IAAI;IAEnD,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,WAAW,CAA6B;gBAG9C,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EACrB,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE;IAY/C,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,KAAK,IAAI,IAAI;IAOP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B,OAAO,CAAC,YAAY;YAMN,IAAI;YAoBJ,MAAM;CAiDrB"}
package/dist/worker.js CHANGED
@@ -7,7 +7,7 @@ export class JobWorker {
7
7
  abortController = null;
8
8
  timer = null;
9
9
  running = false;
10
- processing = false;
10
+ activeCount = 0;
11
11
  stopResolve = null;
12
12
  constructor(queue, options) {
13
13
  this.queue = queue;
@@ -35,7 +35,7 @@ export class JobWorker {
35
35
  this.timer = null;
36
36
  }
37
37
  this.abortController?.abort();
38
- if (this.processing) {
38
+ if (this.activeCount > 0) {
39
39
  return new Promise(resolve => {
40
40
  this.stopResolve = resolve;
41
41
  });
@@ -50,16 +50,21 @@ export class JobWorker {
50
50
  async poll() {
51
51
  if (!this.running)
52
52
  return;
53
- if (this.rateLimiter && !this.rateLimiter.canProceed()) {
54
- this.scheduleNext();
55
- return;
56
- }
57
- const job = this.queue.pollAndClaim(this.options.type);
58
- if (!job) {
59
- this.scheduleNext();
60
- return;
53
+ const concurrency = this.options.concurrency ?? 1;
54
+ // Drain available jobs up to available capacity in one poll tick
55
+ while (this.activeCount < concurrency) {
56
+ if (this.rateLimiter && !this.rateLimiter.canProceed())
57
+ break;
58
+ const job = this.queue.pollAndClaim(this.options.type);
59
+ if (!job)
60
+ break;
61
+ this.rateLimiter?.record();
62
+ this.activeCount++;
63
+ void this.runJob(job);
61
64
  }
62
- this.processing = true;
65
+ this.scheduleNext();
66
+ }
67
+ async runJob(job) {
63
68
  try {
64
69
  const ctx = {
65
70
  reportProgress: (percent) => {
@@ -67,7 +72,6 @@ export class JobWorker {
67
72
  },
68
73
  signal: this.abortController.signal
69
74
  };
70
- this.rateLimiter?.record();
71
75
  const handlerPromise = this.options.handler(job, ctx);
72
76
  if (this.options.timeoutMs) {
73
77
  const timeoutMs = this.options.timeoutMs;
@@ -98,14 +102,11 @@ export class JobWorker {
98
102
  this.options.onError?.(job, error);
99
103
  }
100
104
  finally {
101
- this.processing = false;
102
- if (this.stopResolve) {
105
+ this.activeCount--;
106
+ if (!this.running && this.activeCount === 0 && this.stopResolve) {
103
107
  this.stopResolve();
104
108
  this.stopResolve = null;
105
109
  }
106
- else {
107
- this.scheduleNext();
108
- }
109
110
  }
110
111
  }
111
112
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitclaw/jobs",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "SQLite-backed background job queue using bun:sqlite",
5
5
  "files": [
6
6
  "dist",