workmatic 1.0.5 → 1.0.7
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/README.md +54 -13
- package/dashboard/app.js +1 -3
- package/dashboard/index.html +0 -14
- package/dist/cli.cjs +4 -6
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -6
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +117 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -6
- package/dist/index.d.ts +41 -6
- package/dist/index.js +115 -25
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import * as http from 'http';
|
|
2
1
|
import * as better_sqlite3 from 'better-sqlite3';
|
|
2
|
+
import better_sqlite3__default from 'better-sqlite3';
|
|
3
|
+
import * as http from 'http';
|
|
3
4
|
import { Kysely, Generated } from 'kysely';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Job status types
|
|
7
8
|
*/
|
|
8
|
-
type JobStatus = 'ready' | 'running' | 'done' | '
|
|
9
|
+
type JobStatus = 'ready' | 'running' | 'done' | 'dead';
|
|
9
10
|
/**
|
|
10
11
|
* Database table schema for workmatic_jobs
|
|
11
12
|
*/
|
|
@@ -63,7 +64,7 @@ interface Job<TPayload = unknown> {
|
|
|
63
64
|
maxAttempts: number;
|
|
64
65
|
/** When the job was created (unix ms) */
|
|
65
66
|
createdAt: number;
|
|
66
|
-
/** Last error
|
|
67
|
+
/** Last error from a previous attempt (e.g. before retry) */
|
|
67
68
|
lastError: string | null;
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
@@ -84,6 +85,13 @@ interface AddJobResult {
|
|
|
84
85
|
ok: true;
|
|
85
86
|
id: string;
|
|
86
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Result of adding multiple jobs in one transaction
|
|
90
|
+
*/
|
|
91
|
+
interface AddManyResult {
|
|
92
|
+
ok: true;
|
|
93
|
+
ids: string[];
|
|
94
|
+
}
|
|
87
95
|
/**
|
|
88
96
|
* Options for creating a database
|
|
89
97
|
*/
|
|
@@ -124,7 +132,7 @@ interface WorkerOptions {
|
|
|
124
132
|
leaseMs?: number;
|
|
125
133
|
/** Poll interval in ms when no jobs available. Default: 1000 */
|
|
126
134
|
pollMs?: number;
|
|
127
|
-
/** Job execution timeout in ms. Default:
|
|
135
|
+
/** Job execution timeout in ms. Default: 60000 (1 min). Set to 0 to disable. */
|
|
128
136
|
timeoutMs?: number;
|
|
129
137
|
/** Backoff function for retries. Default: exponential */
|
|
130
138
|
backoff?: BackoffFunction;
|
|
@@ -132,6 +140,18 @@ interface WorkerOptions {
|
|
|
132
140
|
persistState?: boolean;
|
|
133
141
|
/** Auto-restore worker state on creation. Default: true (only applies if persistState is true) */
|
|
134
142
|
autoRestore?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Minimum interval between database pause checks (CLI `pause`). Reduces round-trips while pumping.
|
|
145
|
+
* Default: 300 ms
|
|
146
|
+
*/
|
|
147
|
+
pauseCheckIntervalMs?: number;
|
|
148
|
+
/**
|
|
149
|
+
* Minimum interval between lease requeue scans. Default: every pump (0).
|
|
150
|
+
* Set to e.g. 1000 to run expired-lease recovery at most once per second.
|
|
151
|
+
*/
|
|
152
|
+
requeueExpiredIntervalMs?: number;
|
|
153
|
+
/** Called when the pump loop catches an error (after optional default logging) */
|
|
154
|
+
onPumpError?: (error: unknown) => void;
|
|
135
155
|
}
|
|
136
156
|
/**
|
|
137
157
|
* Job processor function type
|
|
@@ -144,7 +164,6 @@ interface JobStats {
|
|
|
144
164
|
ready: number;
|
|
145
165
|
running: number;
|
|
146
166
|
done: number;
|
|
147
|
-
failed: number;
|
|
148
167
|
dead: number;
|
|
149
168
|
total: number;
|
|
150
169
|
}
|
|
@@ -154,6 +173,11 @@ interface JobStats {
|
|
|
154
173
|
interface WorkmaticClient {
|
|
155
174
|
/** Add a job to the queue */
|
|
156
175
|
add<TPayload = unknown>(payload: TPayload, options?: AddJobOptions): Promise<AddJobResult>;
|
|
176
|
+
/**
|
|
177
|
+
* Add many jobs in a single transaction (shared priority, delay, maxAttempts).
|
|
178
|
+
* Faster than repeated `add()` when inserting large batches.
|
|
179
|
+
*/
|
|
180
|
+
addMany<TPayload = unknown>(payloads: TPayload[], options?: AddJobOptions): Promise<AddManyResult>;
|
|
157
181
|
/** Get job statistics */
|
|
158
182
|
stats(): Promise<JobStats>;
|
|
159
183
|
/** Clear all jobs from the queue */
|
|
@@ -235,6 +259,9 @@ interface ClaimedJob {
|
|
|
235
259
|
payload: string;
|
|
236
260
|
attempts: number;
|
|
237
261
|
max_attempts: number;
|
|
262
|
+
priority: number;
|
|
263
|
+
created_at: number;
|
|
264
|
+
last_error: string | null;
|
|
238
265
|
}
|
|
239
266
|
|
|
240
267
|
/**
|
|
@@ -258,6 +285,12 @@ interface ClaimedJob {
|
|
|
258
285
|
* ```
|
|
259
286
|
*/
|
|
260
287
|
declare function createDatabase(options?: DatabaseOptions): WorkmaticDb;
|
|
288
|
+
/**
|
|
289
|
+
* Get the underlying better-sqlite3 database instance from a Kysely instance
|
|
290
|
+
* created with {@link createDatabase}. For manually constructed `Kysely` instances,
|
|
291
|
+
* falls back to reading the dialect adapter (may break across Kysely versions).
|
|
292
|
+
*/
|
|
293
|
+
declare function getUnderlyingDb(db: WorkmaticDb): better_sqlite3__default.Database;
|
|
261
294
|
|
|
262
295
|
/**
|
|
263
296
|
* Create a job queue client for adding jobs
|
|
@@ -286,6 +319,8 @@ declare function createDatabase(options?: DatabaseOptions): WorkmaticDb;
|
|
|
286
319
|
*/
|
|
287
320
|
declare function createClient(options: ClientOptions): WorkmaticClient;
|
|
288
321
|
|
|
322
|
+
/** Default job execution timeout when `timeoutMs` is omitted (1 minute). Use `timeoutMs: 0` for no limit. */
|
|
323
|
+
declare const DEFAULT_WORKER_TIMEOUT_MS = 60000;
|
|
289
324
|
/**
|
|
290
325
|
* Create a job queue worker for processing jobs
|
|
291
326
|
*
|
|
@@ -383,4 +418,4 @@ declare const defaultBackoff: BackoffFunction;
|
|
|
383
418
|
*/
|
|
384
419
|
declare function validatePayload(payload: unknown): string;
|
|
385
420
|
|
|
386
|
-
export { type AddJobOptions, type AddJobResult, type BackoffFunction, type ClaimedJob, type ClientOptions, type DashboardMiddleware, type DashboardMiddlewareOptions, type DashboardOptions, type DatabaseOptions, type Job, type JobProcessor, type JobStats, type JobStatus, type WorkerOptions, type WorkerState, type WorkmaticClient, type WorkmaticDashboard, type WorkmaticDatabase, type WorkmaticDb, type WorkmaticJobsTable, type WorkmaticWorker, createClient, createDashboard, createDashboardMiddleware, createDatabase, createWorker, defaultBackoff, validatePayload };
|
|
421
|
+
export { type AddJobOptions, type AddJobResult, type AddManyResult, type BackoffFunction, type ClaimedJob, type ClientOptions, DEFAULT_WORKER_TIMEOUT_MS, type DashboardMiddleware, type DashboardMiddlewareOptions, type DashboardOptions, type DatabaseOptions, type Job, type JobProcessor, type JobStats, type JobStatus, type WorkerOptions, type WorkerState, type WorkmaticClient, type WorkmaticDashboard, type WorkmaticDatabase, type WorkmaticDb, type WorkmaticJobsTable, type WorkmaticWorker, createClient, createDashboard, createDashboardMiddleware, createDatabase, createWorker, defaultBackoff, getUnderlyingDb, validatePayload };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import * as http from 'http';
|
|
2
1
|
import * as better_sqlite3 from 'better-sqlite3';
|
|
2
|
+
import better_sqlite3__default from 'better-sqlite3';
|
|
3
|
+
import * as http from 'http';
|
|
3
4
|
import { Kysely, Generated } from 'kysely';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Job status types
|
|
7
8
|
*/
|
|
8
|
-
type JobStatus = 'ready' | 'running' | 'done' | '
|
|
9
|
+
type JobStatus = 'ready' | 'running' | 'done' | 'dead';
|
|
9
10
|
/**
|
|
10
11
|
* Database table schema for workmatic_jobs
|
|
11
12
|
*/
|
|
@@ -63,7 +64,7 @@ interface Job<TPayload = unknown> {
|
|
|
63
64
|
maxAttempts: number;
|
|
64
65
|
/** When the job was created (unix ms) */
|
|
65
66
|
createdAt: number;
|
|
66
|
-
/** Last error
|
|
67
|
+
/** Last error from a previous attempt (e.g. before retry) */
|
|
67
68
|
lastError: string | null;
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
@@ -84,6 +85,13 @@ interface AddJobResult {
|
|
|
84
85
|
ok: true;
|
|
85
86
|
id: string;
|
|
86
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Result of adding multiple jobs in one transaction
|
|
90
|
+
*/
|
|
91
|
+
interface AddManyResult {
|
|
92
|
+
ok: true;
|
|
93
|
+
ids: string[];
|
|
94
|
+
}
|
|
87
95
|
/**
|
|
88
96
|
* Options for creating a database
|
|
89
97
|
*/
|
|
@@ -124,7 +132,7 @@ interface WorkerOptions {
|
|
|
124
132
|
leaseMs?: number;
|
|
125
133
|
/** Poll interval in ms when no jobs available. Default: 1000 */
|
|
126
134
|
pollMs?: number;
|
|
127
|
-
/** Job execution timeout in ms. Default:
|
|
135
|
+
/** Job execution timeout in ms. Default: 60000 (1 min). Set to 0 to disable. */
|
|
128
136
|
timeoutMs?: number;
|
|
129
137
|
/** Backoff function for retries. Default: exponential */
|
|
130
138
|
backoff?: BackoffFunction;
|
|
@@ -132,6 +140,18 @@ interface WorkerOptions {
|
|
|
132
140
|
persistState?: boolean;
|
|
133
141
|
/** Auto-restore worker state on creation. Default: true (only applies if persistState is true) */
|
|
134
142
|
autoRestore?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Minimum interval between database pause checks (CLI `pause`). Reduces round-trips while pumping.
|
|
145
|
+
* Default: 300 ms
|
|
146
|
+
*/
|
|
147
|
+
pauseCheckIntervalMs?: number;
|
|
148
|
+
/**
|
|
149
|
+
* Minimum interval between lease requeue scans. Default: every pump (0).
|
|
150
|
+
* Set to e.g. 1000 to run expired-lease recovery at most once per second.
|
|
151
|
+
*/
|
|
152
|
+
requeueExpiredIntervalMs?: number;
|
|
153
|
+
/** Called when the pump loop catches an error (after optional default logging) */
|
|
154
|
+
onPumpError?: (error: unknown) => void;
|
|
135
155
|
}
|
|
136
156
|
/**
|
|
137
157
|
* Job processor function type
|
|
@@ -144,7 +164,6 @@ interface JobStats {
|
|
|
144
164
|
ready: number;
|
|
145
165
|
running: number;
|
|
146
166
|
done: number;
|
|
147
|
-
failed: number;
|
|
148
167
|
dead: number;
|
|
149
168
|
total: number;
|
|
150
169
|
}
|
|
@@ -154,6 +173,11 @@ interface JobStats {
|
|
|
154
173
|
interface WorkmaticClient {
|
|
155
174
|
/** Add a job to the queue */
|
|
156
175
|
add<TPayload = unknown>(payload: TPayload, options?: AddJobOptions): Promise<AddJobResult>;
|
|
176
|
+
/**
|
|
177
|
+
* Add many jobs in a single transaction (shared priority, delay, maxAttempts).
|
|
178
|
+
* Faster than repeated `add()` when inserting large batches.
|
|
179
|
+
*/
|
|
180
|
+
addMany<TPayload = unknown>(payloads: TPayload[], options?: AddJobOptions): Promise<AddManyResult>;
|
|
157
181
|
/** Get job statistics */
|
|
158
182
|
stats(): Promise<JobStats>;
|
|
159
183
|
/** Clear all jobs from the queue */
|
|
@@ -235,6 +259,9 @@ interface ClaimedJob {
|
|
|
235
259
|
payload: string;
|
|
236
260
|
attempts: number;
|
|
237
261
|
max_attempts: number;
|
|
262
|
+
priority: number;
|
|
263
|
+
created_at: number;
|
|
264
|
+
last_error: string | null;
|
|
238
265
|
}
|
|
239
266
|
|
|
240
267
|
/**
|
|
@@ -258,6 +285,12 @@ interface ClaimedJob {
|
|
|
258
285
|
* ```
|
|
259
286
|
*/
|
|
260
287
|
declare function createDatabase(options?: DatabaseOptions): WorkmaticDb;
|
|
288
|
+
/**
|
|
289
|
+
* Get the underlying better-sqlite3 database instance from a Kysely instance
|
|
290
|
+
* created with {@link createDatabase}. For manually constructed `Kysely` instances,
|
|
291
|
+
* falls back to reading the dialect adapter (may break across Kysely versions).
|
|
292
|
+
*/
|
|
293
|
+
declare function getUnderlyingDb(db: WorkmaticDb): better_sqlite3__default.Database;
|
|
261
294
|
|
|
262
295
|
/**
|
|
263
296
|
* Create a job queue client for adding jobs
|
|
@@ -286,6 +319,8 @@ declare function createDatabase(options?: DatabaseOptions): WorkmaticDb;
|
|
|
286
319
|
*/
|
|
287
320
|
declare function createClient(options: ClientOptions): WorkmaticClient;
|
|
288
321
|
|
|
322
|
+
/** Default job execution timeout when `timeoutMs` is omitted (1 minute). Use `timeoutMs: 0` for no limit. */
|
|
323
|
+
declare const DEFAULT_WORKER_TIMEOUT_MS = 60000;
|
|
289
324
|
/**
|
|
290
325
|
* Create a job queue worker for processing jobs
|
|
291
326
|
*
|
|
@@ -383,4 +418,4 @@ declare const defaultBackoff: BackoffFunction;
|
|
|
383
418
|
*/
|
|
384
419
|
declare function validatePayload(payload: unknown): string;
|
|
385
420
|
|
|
386
|
-
export { type AddJobOptions, type AddJobResult, type BackoffFunction, type ClaimedJob, type ClientOptions, type DashboardMiddleware, type DashboardMiddlewareOptions, type DashboardOptions, type DatabaseOptions, type Job, type JobProcessor, type JobStats, type JobStatus, type WorkerOptions, type WorkerState, type WorkmaticClient, type WorkmaticDashboard, type WorkmaticDatabase, type WorkmaticDb, type WorkmaticJobsTable, type WorkmaticWorker, createClient, createDashboard, createDashboardMiddleware, createDatabase, createWorker, defaultBackoff, validatePayload };
|
|
421
|
+
export { type AddJobOptions, type AddJobResult, type AddManyResult, type BackoffFunction, type ClaimedJob, type ClientOptions, DEFAULT_WORKER_TIMEOUT_MS, type DashboardMiddleware, type DashboardMiddlewareOptions, type DashboardOptions, type DatabaseOptions, type Job, type JobProcessor, type JobStats, type JobStatus, type WorkerOptions, type WorkerState, type WorkmaticClient, type WorkmaticDashboard, type WorkmaticDatabase, type WorkmaticDb, type WorkmaticJobsTable, type WorkmaticWorker, createClient, createDashboard, createDashboardMiddleware, createDatabase, createWorker, defaultBackoff, getUnderlyingDb, validatePayload };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/database.ts
|
|
2
2
|
import Database from "better-sqlite3";
|
|
3
3
|
import { Kysely, SqliteDialect } from "kysely";
|
|
4
|
+
var kyselyToSqlite = /* @__PURE__ */ new WeakMap();
|
|
4
5
|
function createDatabase(options = {}) {
|
|
5
6
|
let sqliteDb;
|
|
6
7
|
if (options.db) {
|
|
@@ -18,6 +19,7 @@ function createDatabase(options = {}) {
|
|
|
18
19
|
})
|
|
19
20
|
});
|
|
20
21
|
createSchema(sqliteDb);
|
|
22
|
+
kyselyToSqlite.set(db, sqliteDb);
|
|
21
23
|
return db;
|
|
22
24
|
}
|
|
23
25
|
function createSchema(db) {
|
|
@@ -53,6 +55,26 @@ function createSchema(db) {
|
|
|
53
55
|
updated_at INTEGER NOT NULL
|
|
54
56
|
)
|
|
55
57
|
`);
|
|
58
|
+
db.exec(`
|
|
59
|
+
UPDATE workmatic_jobs SET status = 'dead' WHERE status = 'failed'
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
function getUnderlyingDb(db) {
|
|
63
|
+
const mapped = kyselyToSqlite.get(db);
|
|
64
|
+
if (mapped) {
|
|
65
|
+
return mapped;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const ex = db.getExecutor?.();
|
|
69
|
+
const dialect = ex?.adapter?.db;
|
|
70
|
+
if (dialect) {
|
|
71
|
+
return dialect;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
throw new Error(
|
|
76
|
+
"getUnderlyingDb: could not resolve better-sqlite3 instance (use createDatabase() or pass db from it)"
|
|
77
|
+
);
|
|
56
78
|
}
|
|
57
79
|
|
|
58
80
|
// src/client.ts
|
|
@@ -121,6 +143,42 @@ function createClient(options) {
|
|
|
121
143
|
}).execute();
|
|
122
144
|
return { ok: true, id: publicId };
|
|
123
145
|
},
|
|
146
|
+
async addMany(payloads, opts = {}) {
|
|
147
|
+
const {
|
|
148
|
+
priority = 0,
|
|
149
|
+
delayMs = 0,
|
|
150
|
+
maxAttempts = 3
|
|
151
|
+
} = opts;
|
|
152
|
+
if (payloads.length === 0) {
|
|
153
|
+
return { ok: true, ids: [] };
|
|
154
|
+
}
|
|
155
|
+
const timestamp = now();
|
|
156
|
+
const runAt = timestamp + delayMs;
|
|
157
|
+
return await db.transaction().execute(async (trx) => {
|
|
158
|
+
const ids = [];
|
|
159
|
+
const rows = payloads.map((payload) => {
|
|
160
|
+
const payloadJson = validatePayload(payload);
|
|
161
|
+
const publicId = nanoid();
|
|
162
|
+
ids.push(publicId);
|
|
163
|
+
return {
|
|
164
|
+
public_id: publicId,
|
|
165
|
+
queue,
|
|
166
|
+
payload: payloadJson,
|
|
167
|
+
status: "ready",
|
|
168
|
+
priority,
|
|
169
|
+
run_at: runAt,
|
|
170
|
+
attempts: 0,
|
|
171
|
+
max_attempts: maxAttempts,
|
|
172
|
+
lease_until: 0,
|
|
173
|
+
created_at: timestamp,
|
|
174
|
+
updated_at: timestamp,
|
|
175
|
+
last_error: null
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
await trx.insertInto("workmatic_jobs").values(rows).execute();
|
|
179
|
+
return { ok: true, ids };
|
|
180
|
+
});
|
|
181
|
+
},
|
|
124
182
|
/**
|
|
125
183
|
* Get job statistics for the queue
|
|
126
184
|
*/
|
|
@@ -133,7 +191,6 @@ function createClient(options) {
|
|
|
133
191
|
ready: 0,
|
|
134
192
|
running: 0,
|
|
135
193
|
done: 0,
|
|
136
|
-
failed: 0,
|
|
137
194
|
dead: 0,
|
|
138
195
|
total: 0
|
|
139
196
|
};
|
|
@@ -164,6 +221,7 @@ function createClient(options) {
|
|
|
164
221
|
// src/worker.ts
|
|
165
222
|
import fastq from "fastq";
|
|
166
223
|
import { sql as sql2 } from "kysely";
|
|
224
|
+
var DEFAULT_WORKER_TIMEOUT_MS = 6e4;
|
|
167
225
|
function createWorker(options) {
|
|
168
226
|
const {
|
|
169
227
|
db,
|
|
@@ -171,10 +229,13 @@ function createWorker(options) {
|
|
|
171
229
|
concurrency = 1,
|
|
172
230
|
leaseMs = 3e4,
|
|
173
231
|
pollMs = 1e3,
|
|
174
|
-
timeoutMs,
|
|
232
|
+
timeoutMs = DEFAULT_WORKER_TIMEOUT_MS,
|
|
175
233
|
backoff = defaultBackoff,
|
|
176
234
|
persistState = false,
|
|
177
|
-
autoRestore = true
|
|
235
|
+
autoRestore = true,
|
|
236
|
+
pauseCheckIntervalMs = 300,
|
|
237
|
+
requeueExpiredIntervalMs = 0,
|
|
238
|
+
onPumpError
|
|
178
239
|
} = options;
|
|
179
240
|
if (!db) {
|
|
180
241
|
throw new Error("Database instance is required");
|
|
@@ -184,6 +245,13 @@ function createWorker(options) {
|
|
|
184
245
|
let processor = null;
|
|
185
246
|
let pumpTimeout = null;
|
|
186
247
|
let fastqQueue = null;
|
|
248
|
+
let lastPauseCheckAt = 0;
|
|
249
|
+
let cachedDbPaused = false;
|
|
250
|
+
let lastRequeueAt = 0;
|
|
251
|
+
function notifyPumpError(error) {
|
|
252
|
+
console.error("[workmatic] Pump error:", error);
|
|
253
|
+
onPumpError?.(error);
|
|
254
|
+
}
|
|
187
255
|
function getStateKey() {
|
|
188
256
|
return `worker_state_${queue}`;
|
|
189
257
|
}
|
|
@@ -191,8 +259,6 @@ function createWorker(options) {
|
|
|
191
259
|
if (!persistState) return;
|
|
192
260
|
const timestamp = now();
|
|
193
261
|
const key = getStateKey();
|
|
194
|
-
await db.schema.createTable("workmatic_settings").ifNotExists().addColumn("queue", "text", (col) => col.primaryKey()).addColumn("paused", "integer", (col) => col.notNull().defaultTo(0)).addColumn("updated_at", "integer", (col) => col.notNull()).execute().catch(() => {
|
|
195
|
-
});
|
|
196
262
|
await sql2`
|
|
197
263
|
INSERT INTO workmatic_settings (queue, paused, updated_at)
|
|
198
264
|
VALUES (${key}, ${state === "paused" ? 1 : state === "running" ? 2 : 0}, ${timestamp})
|
|
@@ -227,17 +293,34 @@ function createWorker(options) {
|
|
|
227
293
|
const timestamp = now();
|
|
228
294
|
const leaseUntil = timestamp + leaseMs;
|
|
229
295
|
return await db.transaction().execute(async (trx) => {
|
|
230
|
-
const
|
|
231
|
-
|
|
296
|
+
const result = await sql2`
|
|
297
|
+
UPDATE workmatic_jobs
|
|
298
|
+
SET status = 'running', lease_until = ${leaseUntil}, updated_at = ${timestamp}
|
|
299
|
+
WHERE rowid IN (
|
|
300
|
+
SELECT rowid FROM workmatic_jobs
|
|
301
|
+
WHERE queue = ${queue}
|
|
302
|
+
AND status = 'ready'
|
|
303
|
+
AND run_at <= ${timestamp}
|
|
304
|
+
ORDER BY priority ASC, id ASC
|
|
305
|
+
LIMIT ${limit}
|
|
306
|
+
)
|
|
307
|
+
RETURNING id, public_id, queue, payload, attempts, max_attempts, priority, created_at, last_error
|
|
308
|
+
`.execute(trx);
|
|
309
|
+
const rows = result.rows;
|
|
310
|
+
if (!rows || !Array.isArray(rows)) {
|
|
232
311
|
return [];
|
|
233
312
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
313
|
+
return rows.map((row) => ({
|
|
314
|
+
id: row.id,
|
|
315
|
+
public_id: row.public_id,
|
|
316
|
+
queue: row.queue,
|
|
317
|
+
payload: row.payload,
|
|
318
|
+
attempts: row.attempts,
|
|
319
|
+
max_attempts: row.max_attempts,
|
|
320
|
+
priority: row.priority,
|
|
321
|
+
created_at: row.created_at,
|
|
322
|
+
last_error: row.last_error
|
|
323
|
+
}));
|
|
241
324
|
});
|
|
242
325
|
}
|
|
243
326
|
async function markDone(jobId) {
|
|
@@ -294,13 +377,11 @@ function createWorker(options) {
|
|
|
294
377
|
queue: claimedJob.queue,
|
|
295
378
|
payload,
|
|
296
379
|
status: "running",
|
|
297
|
-
priority:
|
|
298
|
-
// Not needed for processing
|
|
380
|
+
priority: claimedJob.priority,
|
|
299
381
|
attempts: claimedJob.attempts,
|
|
300
382
|
maxAttempts: claimedJob.max_attempts,
|
|
301
|
-
createdAt:
|
|
302
|
-
|
|
303
|
-
lastError: null
|
|
383
|
+
createdAt: claimedJob.created_at,
|
|
384
|
+
lastError: claimedJob.last_error
|
|
304
385
|
};
|
|
305
386
|
try {
|
|
306
387
|
if (timeoutMs) {
|
|
@@ -331,12 +412,21 @@ function createWorker(options) {
|
|
|
331
412
|
return;
|
|
332
413
|
}
|
|
333
414
|
try {
|
|
334
|
-
const
|
|
335
|
-
if (
|
|
415
|
+
const t = now();
|
|
416
|
+
if (t - lastPauseCheckAt >= pauseCheckIntervalMs) {
|
|
417
|
+
lastPauseCheckAt = t;
|
|
418
|
+
cachedDbPaused = await isQueuePausedInDb();
|
|
419
|
+
}
|
|
420
|
+
if (cachedDbPaused) {
|
|
336
421
|
pumpTimeout = setTimeout(pump, pollMs);
|
|
337
422
|
return;
|
|
338
423
|
}
|
|
339
|
-
|
|
424
|
+
if (requeueExpiredIntervalMs <= 0 || t - lastRequeueAt >= requeueExpiredIntervalMs) {
|
|
425
|
+
if (requeueExpiredIntervalMs > 0) {
|
|
426
|
+
lastRequeueAt = t;
|
|
427
|
+
}
|
|
428
|
+
await requeueExpiredLeases();
|
|
429
|
+
}
|
|
340
430
|
const batchSize = concurrency * 2;
|
|
341
431
|
const jobs = await claimBatch(batchSize);
|
|
342
432
|
if (jobs.length > 0) {
|
|
@@ -348,7 +438,7 @@ function createWorker(options) {
|
|
|
348
438
|
pumpTimeout = setTimeout(pump, pollMs);
|
|
349
439
|
}
|
|
350
440
|
} catch (error) {
|
|
351
|
-
|
|
441
|
+
notifyPumpError(error);
|
|
352
442
|
pumpTimeout = setTimeout(pump, pollMs);
|
|
353
443
|
}
|
|
354
444
|
}
|
|
@@ -404,7 +494,6 @@ function createWorker(options) {
|
|
|
404
494
|
ready: 0,
|
|
405
495
|
running: 0,
|
|
406
496
|
done: 0,
|
|
407
|
-
failed: 0,
|
|
408
497
|
dead: 0,
|
|
409
498
|
total: 0
|
|
410
499
|
};
|
|
@@ -547,7 +636,6 @@ function createRequestHandler(db, workerMap, basePath = "") {
|
|
|
547
636
|
ready: 0,
|
|
548
637
|
running: 0,
|
|
549
638
|
done: 0,
|
|
550
|
-
failed: 0,
|
|
551
639
|
dead: 0,
|
|
552
640
|
total: 0
|
|
553
641
|
};
|
|
@@ -753,12 +841,14 @@ function createDashboardMiddleware(options) {
|
|
|
753
841
|
};
|
|
754
842
|
}
|
|
755
843
|
export {
|
|
844
|
+
DEFAULT_WORKER_TIMEOUT_MS,
|
|
756
845
|
createClient,
|
|
757
846
|
createDashboard,
|
|
758
847
|
createDashboardMiddleware,
|
|
759
848
|
createDatabase,
|
|
760
849
|
createWorker,
|
|
761
850
|
defaultBackoff,
|
|
851
|
+
getUnderlyingDb,
|
|
762
852
|
validatePayload
|
|
763
853
|
};
|
|
764
854
|
//# sourceMappingURL=index.js.map
|