@objectstack/service-queue 4.0.5 → 4.1.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/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Plugin, PluginContext } from '@objectstack/core';
2
- import { IQueueService, QueuePublishOptions, QueueHandler } from '@objectstack/spec/contracts';
2
+ import { IQueueService, QueuePublishOptions, QueueHandler, QueueMessageRecord } from '@objectstack/spec/contracts';
3
3
 
4
4
  /**
5
5
  * Configuration options for MemoryQueueAdapter.
@@ -27,43 +27,136 @@ declare class MemoryQueueAdapter implements IQueueService {
27
27
  purge(queue: string): Promise<void>;
28
28
  }
29
29
 
30
+ /**
31
+ * Narrow ObjectQL engine surface used by job/queue adapters.
32
+ * Keeps the adapter testable without booting a real kernel.
33
+ *
34
+ * IMPORTANT: matches the canonical engine API:
35
+ * - find: `where:` (NOT `filter:`)
36
+ * - update: `(table, {id, ...patch}, opts)`
37
+ */
38
+ interface JobEngine {
39
+ find(object: string, options?: any): Promise<any[]>;
40
+ insert(object: string, data: any, options?: any): Promise<any>;
41
+ update(object: string, idOrData: any, dataOrOptions?: any, options?: any): Promise<any>;
42
+ delete(object: string, options?: any): Promise<any>;
43
+ }
44
+ /** Stamped only in tests to make `now` deterministic. */
45
+ interface JobClock {
46
+ now(): Date;
47
+ }
48
+ interface JobLogger {
49
+ info(msg: string, meta?: unknown): void;
50
+ warn(msg: string, meta?: unknown): void;
51
+ error?(msg: string, meta?: unknown): void;
52
+ }
53
+
54
+ interface DbQueueAdapterOptions {
55
+ /** Polling interval for the worker loop (ms, default 1000) */
56
+ pollIntervalMs?: number;
57
+ /** Max messages claimed per poll tick (default 10) */
58
+ batchSize?: number;
59
+ /** Lease duration before another worker may reclaim (ms, default 30000) */
60
+ leaseMs?: number;
61
+ /** Idempotency window — how long the same key blocks re-publish (ms, default 24h) */
62
+ idempotencyWindowMs?: number;
63
+ /** Default maxAttempts when publish doesn't specify (default 3) */
64
+ defaultMaxAttempts?: number;
65
+ /** Unique identifier for this worker (default: random) */
66
+ workerId?: string;
67
+ /** Whether to auto-start the polling worker (default true) */
68
+ autoStart?: boolean;
69
+ }
70
+ /**
71
+ * DbQueueAdapter — durable, polling, DB-backed IQueueService.
72
+ *
73
+ * Persists every message to `sys_job_queue`. A polling worker leases
74
+ * pending messages (CAS update status pending→running with a lease),
75
+ * invokes registered subscribers, and retries with backoff on failure.
76
+ * Messages that exceed `max_attempts` land in `status='dlq'`.
77
+ *
78
+ * Idempotency: publish suppresses duplicates within a configurable
79
+ * window when `(queue, idempotencyKey)` is non-null.
80
+ *
81
+ * Designed for SQLite and Postgres alike — uses CAS via WHERE-clauses,
82
+ * not row-level locking.
83
+ */
84
+ declare class DbQueueAdapter implements IQueueService {
85
+ private readonly engine;
86
+ private readonly logger?;
87
+ private readonly clock?;
88
+ private readonly opts;
89
+ private readonly handlers;
90
+ private timer?;
91
+ private running;
92
+ constructor(args: {
93
+ engine: JobEngine;
94
+ logger?: JobLogger;
95
+ clock?: JobClock;
96
+ options?: DbQueueAdapterOptions;
97
+ });
98
+ publish<T = unknown>(queue: string, data: T, options?: QueuePublishOptions): Promise<string>;
99
+ subscribe<T = unknown>(queue: string, handler: QueueHandler<T>): Promise<void>;
100
+ unsubscribe(queue: string): Promise<void>;
101
+ getQueueSize(queue: string): Promise<number>;
102
+ purge(queue: string): Promise<void>;
103
+ listFailed(queue?: string, options?: {
104
+ limit?: number;
105
+ offset?: number;
106
+ }): Promise<QueueMessageRecord[]>;
107
+ replay(messageId: string): Promise<void>;
108
+ purgeFailed(messageId: string): Promise<void>;
109
+ start(): void;
110
+ stop(): Promise<void>;
111
+ /** Test-friendly synchronous poll. */
112
+ pollOnce(): Promise<number>;
113
+ private claimBatch;
114
+ private dispatch;
115
+ private computeBackoff;
116
+ private releasePending;
117
+ private loadById;
118
+ private rowToRecord;
119
+ private now;
120
+ }
121
+
30
122
  /**
31
123
  * Configuration options for the QueueServicePlugin.
32
124
  */
33
125
  interface QueueServicePluginOptions {
34
- /** Queue adapter type (default: 'memory') */
35
- adapter?: 'memory' | 'bullmq';
126
+ /**
127
+ * Queue adapter type.
128
+ * - 'auto' (default): use DbQueueAdapter when objectql engine available, else MemoryQueueAdapter
129
+ * - 'db': require objectql; persists messages, retries, and DLQ to sys_job_queue
130
+ * - 'memory': in-process MemoryQueueAdapter (non-durable, dev/test)
131
+ * - 'bullmq': reserved for M10.43 (throws today)
132
+ */
133
+ adapter?: 'auto' | 'db' | 'memory' | 'bullmq';
36
134
  /** Options for the memory queue adapter */
37
135
  memory?: MemoryQueueAdapterOptions;
38
- /** Redis connection URL (used when adapter is 'bullmq') */
136
+ /** Options for the DB adapter (polling, batch, lease, idempotency window…) */
137
+ db?: DbQueueAdapterOptions;
138
+ /** Redis connection URL (reserved for bullmq) */
39
139
  redisUrl?: string;
40
140
  }
41
141
  /**
42
142
  * QueueServicePlugin — Production IQueueService implementation.
43
143
  *
44
- * Registers a queue service with the kernel during the init phase.
45
- * Supports in-memory and BullMQ adapters.
46
- *
47
- * @example
48
- * ```ts
49
- * import { ObjectKernel } from '@objectstack/core';
50
- * import { QueueServicePlugin } from '@objectstack/service-queue';
51
- *
52
- * const kernel = new ObjectKernel();
53
- * kernel.use(new QueueServicePlugin({ adapter: 'memory' }));
54
- * await kernel.bootstrap();
55
- *
56
- * const queue = kernel.getService('queue');
57
- * await queue.publish('orders', { orderId: 123 });
58
- * ```
144
+ * Default: registers MemoryQueueAdapter synchronously so producers can
145
+ * publish during plugin init; upgrades to DbQueueAdapter on `kernel:ready`
146
+ * when an ObjectQL engine is available. Subscribers registered against
147
+ * the (now-replaced) memory queue must re-subscribe after upgrade — for
148
+ * that reason most plugins register subscribers inside their own
149
+ * `kernel:ready` hook, which fires after this one.
59
150
  */
60
151
  declare class QueueServicePlugin implements Plugin {
61
152
  name: string;
62
153
  version: string;
63
154
  type: string;
64
155
  private readonly options;
156
+ private dbAdapter?;
65
157
  constructor(options?: QueueServicePluginOptions);
66
158
  init(ctx: PluginContext): Promise<void>;
159
+ destroy(): Promise<void>;
67
160
  }
68
161
 
69
162
  /**
@@ -105,4 +198,4 @@ declare class BullMQQueueAdapter implements IQueueService {
105
198
  purge(_queue: string): Promise<void>;
106
199
  }
107
200
 
108
- export { BullMQQueueAdapter, type BullMQQueueAdapterOptions, MemoryQueueAdapter, type MemoryQueueAdapterOptions, QueueServicePlugin, type QueueServicePluginOptions };
201
+ export { BullMQQueueAdapter, type BullMQQueueAdapterOptions, DbQueueAdapter, type DbQueueAdapterOptions, type JobClock, type JobEngine, type JobLogger, MemoryQueueAdapter, type MemoryQueueAdapterOptions, QueueServicePlugin, type QueueServicePluginOptions };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Plugin, PluginContext } from '@objectstack/core';
2
- import { IQueueService, QueuePublishOptions, QueueHandler } from '@objectstack/spec/contracts';
2
+ import { IQueueService, QueuePublishOptions, QueueHandler, QueueMessageRecord } from '@objectstack/spec/contracts';
3
3
 
4
4
  /**
5
5
  * Configuration options for MemoryQueueAdapter.
@@ -27,43 +27,136 @@ declare class MemoryQueueAdapter implements IQueueService {
27
27
  purge(queue: string): Promise<void>;
28
28
  }
29
29
 
30
+ /**
31
+ * Narrow ObjectQL engine surface used by job/queue adapters.
32
+ * Keeps the adapter testable without booting a real kernel.
33
+ *
34
+ * IMPORTANT: matches the canonical engine API:
35
+ * - find: `where:` (NOT `filter:`)
36
+ * - update: `(table, {id, ...patch}, opts)`
37
+ */
38
+ interface JobEngine {
39
+ find(object: string, options?: any): Promise<any[]>;
40
+ insert(object: string, data: any, options?: any): Promise<any>;
41
+ update(object: string, idOrData: any, dataOrOptions?: any, options?: any): Promise<any>;
42
+ delete(object: string, options?: any): Promise<any>;
43
+ }
44
+ /** Stamped only in tests to make `now` deterministic. */
45
+ interface JobClock {
46
+ now(): Date;
47
+ }
48
+ interface JobLogger {
49
+ info(msg: string, meta?: unknown): void;
50
+ warn(msg: string, meta?: unknown): void;
51
+ error?(msg: string, meta?: unknown): void;
52
+ }
53
+
54
+ interface DbQueueAdapterOptions {
55
+ /** Polling interval for the worker loop (ms, default 1000) */
56
+ pollIntervalMs?: number;
57
+ /** Max messages claimed per poll tick (default 10) */
58
+ batchSize?: number;
59
+ /** Lease duration before another worker may reclaim (ms, default 30000) */
60
+ leaseMs?: number;
61
+ /** Idempotency window — how long the same key blocks re-publish (ms, default 24h) */
62
+ idempotencyWindowMs?: number;
63
+ /** Default maxAttempts when publish doesn't specify (default 3) */
64
+ defaultMaxAttempts?: number;
65
+ /** Unique identifier for this worker (default: random) */
66
+ workerId?: string;
67
+ /** Whether to auto-start the polling worker (default true) */
68
+ autoStart?: boolean;
69
+ }
70
+ /**
71
+ * DbQueueAdapter — durable, polling, DB-backed IQueueService.
72
+ *
73
+ * Persists every message to `sys_job_queue`. A polling worker leases
74
+ * pending messages (CAS update status pending→running with a lease),
75
+ * invokes registered subscribers, and retries with backoff on failure.
76
+ * Messages that exceed `max_attempts` land in `status='dlq'`.
77
+ *
78
+ * Idempotency: publish suppresses duplicates within a configurable
79
+ * window when `(queue, idempotencyKey)` is non-null.
80
+ *
81
+ * Designed for SQLite and Postgres alike — uses CAS via WHERE-clauses,
82
+ * not row-level locking.
83
+ */
84
+ declare class DbQueueAdapter implements IQueueService {
85
+ private readonly engine;
86
+ private readonly logger?;
87
+ private readonly clock?;
88
+ private readonly opts;
89
+ private readonly handlers;
90
+ private timer?;
91
+ private running;
92
+ constructor(args: {
93
+ engine: JobEngine;
94
+ logger?: JobLogger;
95
+ clock?: JobClock;
96
+ options?: DbQueueAdapterOptions;
97
+ });
98
+ publish<T = unknown>(queue: string, data: T, options?: QueuePublishOptions): Promise<string>;
99
+ subscribe<T = unknown>(queue: string, handler: QueueHandler<T>): Promise<void>;
100
+ unsubscribe(queue: string): Promise<void>;
101
+ getQueueSize(queue: string): Promise<number>;
102
+ purge(queue: string): Promise<void>;
103
+ listFailed(queue?: string, options?: {
104
+ limit?: number;
105
+ offset?: number;
106
+ }): Promise<QueueMessageRecord[]>;
107
+ replay(messageId: string): Promise<void>;
108
+ purgeFailed(messageId: string): Promise<void>;
109
+ start(): void;
110
+ stop(): Promise<void>;
111
+ /** Test-friendly synchronous poll. */
112
+ pollOnce(): Promise<number>;
113
+ private claimBatch;
114
+ private dispatch;
115
+ private computeBackoff;
116
+ private releasePending;
117
+ private loadById;
118
+ private rowToRecord;
119
+ private now;
120
+ }
121
+
30
122
  /**
31
123
  * Configuration options for the QueueServicePlugin.
32
124
  */
33
125
  interface QueueServicePluginOptions {
34
- /** Queue adapter type (default: 'memory') */
35
- adapter?: 'memory' | 'bullmq';
126
+ /**
127
+ * Queue adapter type.
128
+ * - 'auto' (default): use DbQueueAdapter when objectql engine available, else MemoryQueueAdapter
129
+ * - 'db': require objectql; persists messages, retries, and DLQ to sys_job_queue
130
+ * - 'memory': in-process MemoryQueueAdapter (non-durable, dev/test)
131
+ * - 'bullmq': reserved for M10.43 (throws today)
132
+ */
133
+ adapter?: 'auto' | 'db' | 'memory' | 'bullmq';
36
134
  /** Options for the memory queue adapter */
37
135
  memory?: MemoryQueueAdapterOptions;
38
- /** Redis connection URL (used when adapter is 'bullmq') */
136
+ /** Options for the DB adapter (polling, batch, lease, idempotency window…) */
137
+ db?: DbQueueAdapterOptions;
138
+ /** Redis connection URL (reserved for bullmq) */
39
139
  redisUrl?: string;
40
140
  }
41
141
  /**
42
142
  * QueueServicePlugin — Production IQueueService implementation.
43
143
  *
44
- * Registers a queue service with the kernel during the init phase.
45
- * Supports in-memory and BullMQ adapters.
46
- *
47
- * @example
48
- * ```ts
49
- * import { ObjectKernel } from '@objectstack/core';
50
- * import { QueueServicePlugin } from '@objectstack/service-queue';
51
- *
52
- * const kernel = new ObjectKernel();
53
- * kernel.use(new QueueServicePlugin({ adapter: 'memory' }));
54
- * await kernel.bootstrap();
55
- *
56
- * const queue = kernel.getService('queue');
57
- * await queue.publish('orders', { orderId: 123 });
58
- * ```
144
+ * Default: registers MemoryQueueAdapter synchronously so producers can
145
+ * publish during plugin init; upgrades to DbQueueAdapter on `kernel:ready`
146
+ * when an ObjectQL engine is available. Subscribers registered against
147
+ * the (now-replaced) memory queue must re-subscribe after upgrade — for
148
+ * that reason most plugins register subscribers inside their own
149
+ * `kernel:ready` hook, which fires after this one.
59
150
  */
60
151
  declare class QueueServicePlugin implements Plugin {
61
152
  name: string;
62
153
  version: string;
63
154
  type: string;
64
155
  private readonly options;
156
+ private dbAdapter?;
65
157
  constructor(options?: QueueServicePluginOptions);
66
158
  init(ctx: PluginContext): Promise<void>;
159
+ destroy(): Promise<void>;
67
160
  }
68
161
 
69
162
  /**
@@ -105,4 +198,4 @@ declare class BullMQQueueAdapter implements IQueueService {
105
198
  purge(_queue: string): Promise<void>;
106
199
  }
107
200
 
108
- export { BullMQQueueAdapter, type BullMQQueueAdapterOptions, MemoryQueueAdapter, type MemoryQueueAdapterOptions, QueueServicePlugin, type QueueServicePluginOptions };
201
+ export { BullMQQueueAdapter, type BullMQQueueAdapterOptions, DbQueueAdapter, type DbQueueAdapterOptions, type JobClock, type JobEngine, type JobLogger, MemoryQueueAdapter, type MemoryQueueAdapterOptions, QueueServicePlugin, type QueueServicePluginOptions };