@convex-dev/workpool 0.2.0-alpha.0 → 0.2.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/README.md +1 -1
- package/dist/commonjs/client/index.d.ts +3 -3
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +10 -5
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/component/complete.js +1 -1
- package/dist/commonjs/component/complete.js.map +1 -1
- package/dist/commonjs/component/kick.d.ts +0 -1
- package/dist/commonjs/component/kick.d.ts.map +1 -1
- package/dist/commonjs/component/kick.js +6 -4
- package/dist/commonjs/component/kick.js.map +1 -1
- package/dist/commonjs/component/lib.d.ts.map +1 -1
- package/dist/commonjs/component/lib.js +4 -3
- package/dist/commonjs/component/lib.js.map +1 -1
- package/dist/commonjs/component/logging.d.ts.map +1 -1
- package/dist/commonjs/component/logging.js +1 -2
- package/dist/commonjs/component/logging.js.map +1 -1
- package/dist/commonjs/component/loop.d.ts.map +1 -1
- package/dist/commonjs/component/loop.js +46 -38
- package/dist/commonjs/component/loop.js.map +1 -1
- package/dist/commonjs/component/shared.d.ts +1 -0
- package/dist/commonjs/component/shared.d.ts.map +1 -1
- package/dist/commonjs/component/shared.js +1 -0
- package/dist/commonjs/component/shared.js.map +1 -1
- package/dist/commonjs/component/stats.d.ts +19 -13
- package/dist/commonjs/component/stats.d.ts.map +1 -1
- package/dist/commonjs/component/stats.js +26 -21
- package/dist/commonjs/component/stats.js.map +1 -1
- package/dist/esm/client/index.d.ts +3 -3
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +10 -5
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/component/complete.js +1 -1
- package/dist/esm/component/complete.js.map +1 -1
- package/dist/esm/component/kick.d.ts +0 -1
- package/dist/esm/component/kick.d.ts.map +1 -1
- package/dist/esm/component/kick.js +6 -4
- package/dist/esm/component/kick.js.map +1 -1
- package/dist/esm/component/lib.d.ts.map +1 -1
- package/dist/esm/component/lib.js +4 -3
- package/dist/esm/component/lib.js.map +1 -1
- package/dist/esm/component/logging.d.ts.map +1 -1
- package/dist/esm/component/logging.js +1 -2
- package/dist/esm/component/logging.js.map +1 -1
- package/dist/esm/component/loop.d.ts.map +1 -1
- package/dist/esm/component/loop.js +46 -38
- package/dist/esm/component/loop.js.map +1 -1
- package/dist/esm/component/shared.d.ts +1 -0
- package/dist/esm/component/shared.d.ts.map +1 -1
- package/dist/esm/component/shared.js +1 -0
- package/dist/esm/component/shared.js.map +1 -1
- package/dist/esm/component/stats.d.ts +19 -13
- package/dist/esm/component/stats.d.ts.map +1 -1
- package/dist/esm/component/stats.js +26 -21
- package/dist/esm/component/stats.js.map +1 -1
- package/package.json +7 -6
- package/src/client/index.ts +18 -8
- package/src/component/_generated/api.d.ts +3 -0
- package/src/component/complete.test.ts +10 -10
- package/src/component/complete.ts +1 -1
- package/src/component/kick.test.ts +10 -9
- package/src/component/kick.ts +11 -6
- package/src/component/lib.test.ts +20 -20
- package/src/component/lib.ts +4 -2
- package/src/component/logging.ts +1 -2
- package/src/component/loop.test.ts +101 -147
- package/src/component/loop.ts +49 -39
- package/src/component/recovery.test.ts +7 -7
- package/src/component/shared.ts +1 -0
- package/src/component/stats.ts +41 -22
|
@@ -30,7 +30,7 @@ describe("complete", () => {
|
|
|
30
30
|
await t.run(async (ctx) => {
|
|
31
31
|
await ctx.db.insert("globals", {
|
|
32
32
|
maxParallelism: 10,
|
|
33
|
-
logLevel: "
|
|
33
|
+
logLevel: "WARN",
|
|
34
34
|
});
|
|
35
35
|
});
|
|
36
36
|
});
|
|
@@ -50,7 +50,7 @@ describe("complete", () => {
|
|
|
50
50
|
runAt: Date.now(),
|
|
51
51
|
config: {
|
|
52
52
|
maxParallelism: 10,
|
|
53
|
-
logLevel: "
|
|
53
|
+
logLevel: "WARN",
|
|
54
54
|
},
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -95,7 +95,7 @@ describe("complete", () => {
|
|
|
95
95
|
runAt: Date.now(),
|
|
96
96
|
config: {
|
|
97
97
|
maxParallelism: 10,
|
|
98
|
-
logLevel: "
|
|
98
|
+
logLevel: "WARN",
|
|
99
99
|
},
|
|
100
100
|
retryBehavior: {
|
|
101
101
|
maxAttempts: 3,
|
|
@@ -146,7 +146,7 @@ describe("complete", () => {
|
|
|
146
146
|
runAt: Date.now(),
|
|
147
147
|
config: {
|
|
148
148
|
maxParallelism: 10,
|
|
149
|
-
logLevel: "
|
|
149
|
+
logLevel: "WARN",
|
|
150
150
|
},
|
|
151
151
|
retryBehavior: {
|
|
152
152
|
maxAttempts: 2, // Only 1 retry allowed
|
|
@@ -204,7 +204,7 @@ describe("complete", () => {
|
|
|
204
204
|
runAt: Date.now(),
|
|
205
205
|
config: {
|
|
206
206
|
maxParallelism: 10,
|
|
207
|
-
logLevel: "
|
|
207
|
+
logLevel: "WARN",
|
|
208
208
|
},
|
|
209
209
|
});
|
|
210
210
|
|
|
@@ -250,7 +250,7 @@ describe("complete", () => {
|
|
|
250
250
|
runAt: Date.now(),
|
|
251
251
|
config: {
|
|
252
252
|
maxParallelism: 10,
|
|
253
|
-
logLevel: "
|
|
253
|
+
logLevel: "WARN",
|
|
254
254
|
},
|
|
255
255
|
onComplete: {
|
|
256
256
|
fnHandle: "testOnComplete",
|
|
@@ -298,7 +298,7 @@ describe("complete", () => {
|
|
|
298
298
|
runAt: Date.now(),
|
|
299
299
|
config: {
|
|
300
300
|
maxParallelism: 10,
|
|
301
|
-
logLevel: "
|
|
301
|
+
logLevel: "WARN",
|
|
302
302
|
},
|
|
303
303
|
});
|
|
304
304
|
|
|
@@ -310,7 +310,7 @@ describe("complete", () => {
|
|
|
310
310
|
runAt: Date.now(),
|
|
311
311
|
config: {
|
|
312
312
|
maxParallelism: 10,
|
|
313
|
-
logLevel: "
|
|
313
|
+
logLevel: "WARN",
|
|
314
314
|
},
|
|
315
315
|
retryBehavior: {
|
|
316
316
|
maxAttempts: 3,
|
|
@@ -366,7 +366,7 @@ describe("complete", () => {
|
|
|
366
366
|
runAt: Date.now(),
|
|
367
367
|
config: {
|
|
368
368
|
maxParallelism: 10,
|
|
369
|
-
logLevel: "
|
|
369
|
+
logLevel: "WARN",
|
|
370
370
|
},
|
|
371
371
|
});
|
|
372
372
|
|
|
@@ -418,7 +418,7 @@ describe("complete", () => {
|
|
|
418
418
|
runAt: Date.now(),
|
|
419
419
|
config: {
|
|
420
420
|
maxParallelism: 10,
|
|
421
|
-
logLevel: "
|
|
421
|
+
logLevel: "WARN",
|
|
422
422
|
},
|
|
423
423
|
retryBehavior: {
|
|
424
424
|
maxAttempts: 3,
|
|
@@ -72,7 +72,7 @@ export async function completeHandler(
|
|
|
72
72
|
// TODO: store failures in a table for later debugging
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
recordCompleted(console, work, job.runResult.kind);
|
|
76
76
|
// This is the terminating state for work.
|
|
77
77
|
await ctx.db.delete(job.workId);
|
|
78
78
|
}
|
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
test,
|
|
9
9
|
vi,
|
|
10
10
|
} from "vitest";
|
|
11
|
-
import schema from "./schema.js";
|
|
12
|
-
import { modules } from "./setup.test.js";
|
|
13
|
-
import { DEFAULT_MAX_PARALLELISM, kickMainLoop } from "./kick.js";
|
|
14
|
-
import { DEFAULT_LOG_LEVEL } from "./logging.js";
|
|
15
11
|
import { internal } from "./_generated/api";
|
|
16
|
-
import { toSegment, fromSegment, nextSegment } from "./shared";
|
|
17
12
|
import { Id } from "./_generated/dataModel.js";
|
|
13
|
+
import { kickMainLoop } from "./kick.js";
|
|
14
|
+
import { DEFAULT_LOG_LEVEL } from "./logging.js";
|
|
15
|
+
import schema from "./schema.js";
|
|
16
|
+
import { modules } from "./setup.test.js";
|
|
17
|
+
import { fromSegment, nextSegment, toSegment } from "./shared";
|
|
18
|
+
import { DEFAULT_MAX_PARALLELISM } from "./shared.js";
|
|
18
19
|
|
|
19
20
|
describe("kickMainLoop", () => {
|
|
20
21
|
beforeEach(() => {
|
|
@@ -53,13 +54,13 @@ describe("kickMainLoop", () => {
|
|
|
53
54
|
expect(globals.logLevel).toBe(DEFAULT_LOG_LEVEL);
|
|
54
55
|
await kickMainLoop(ctx, "enqueue", {
|
|
55
56
|
maxParallelism: DEFAULT_MAX_PARALLELISM + 1,
|
|
56
|
-
logLevel: "
|
|
57
|
+
logLevel: "ERROR",
|
|
57
58
|
});
|
|
58
59
|
const after = await ctx.db.query("globals").unique();
|
|
59
60
|
expect(after).not.toBeNull();
|
|
60
61
|
assert(after);
|
|
61
62
|
expect(after.maxParallelism).toBe(DEFAULT_MAX_PARALLELISM + 1);
|
|
62
|
-
expect(after.logLevel).toBe("
|
|
63
|
+
expect(after.logLevel).toBe("ERROR");
|
|
63
64
|
});
|
|
64
65
|
});
|
|
65
66
|
|
|
@@ -242,7 +243,7 @@ describe("kickMainLoop", () => {
|
|
|
242
243
|
// Initial kick with custom config
|
|
243
244
|
await kickMainLoop(ctx, "enqueue", {
|
|
244
245
|
maxParallelism: 5,
|
|
245
|
-
logLevel: "
|
|
246
|
+
logLevel: "ERROR",
|
|
246
247
|
});
|
|
247
248
|
|
|
248
249
|
// Kick from different sources
|
|
@@ -254,7 +255,7 @@ describe("kickMainLoop", () => {
|
|
|
254
255
|
expect(globals).not.toBeNull();
|
|
255
256
|
assert(globals);
|
|
256
257
|
expect(globals.maxParallelism).toBe(5);
|
|
257
|
-
expect(globals.logLevel).toBe("
|
|
258
|
+
expect(globals.logLevel).toBe("ERROR");
|
|
258
259
|
});
|
|
259
260
|
});
|
|
260
261
|
|
package/src/component/kick.ts
CHANGED
|
@@ -2,9 +2,14 @@ import { internal } from "./_generated/api.js";
|
|
|
2
2
|
import { internalMutation, MutationCtx } from "./_generated/server.js";
|
|
3
3
|
import { createLogger, DEFAULT_LOG_LEVEL } from "./logging.js";
|
|
4
4
|
import { INITIAL_STATE } from "./loop.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
boundScheduledTime,
|
|
7
|
+
Config,
|
|
8
|
+
DEFAULT_MAX_PARALLELISM,
|
|
9
|
+
fromSegment,
|
|
10
|
+
nextSegment,
|
|
11
|
+
} from "./shared.js";
|
|
6
12
|
|
|
7
|
-
export const DEFAULT_MAX_PARALLELISM = 10;
|
|
8
13
|
/**
|
|
9
14
|
* Called from outside the loop:
|
|
10
15
|
*/
|
|
@@ -51,12 +56,12 @@ export async function kickMainLoop(
|
|
|
51
56
|
`[${source}] main is marked as scheduled, but it's status is ${scheduled?.state.kind}`
|
|
52
57
|
);
|
|
53
58
|
}
|
|
59
|
+
} else if (runStatus.state.kind === "idle") {
|
|
60
|
+
console.debug(`[${source}] main was idle, so run it now`);
|
|
54
61
|
}
|
|
55
|
-
console.debug(
|
|
56
|
-
`[${source}] main was scheduled later, so reschedule it to run now`
|
|
57
|
-
);
|
|
58
62
|
await ctx.db.patch(runStatus._id, { state: { kind: "running" } });
|
|
59
|
-
|
|
63
|
+
const scheduledTime = boundScheduledTime(fromSegment(segment), console);
|
|
64
|
+
await ctx.scheduler.runAt(scheduledTime, internal.loop.main, {
|
|
60
65
|
generation: runStatus.state.generation,
|
|
61
66
|
segment,
|
|
62
67
|
});
|
|
@@ -44,7 +44,7 @@ describe("lib", () => {
|
|
|
44
44
|
runAt: Date.now(),
|
|
45
45
|
config: {
|
|
46
46
|
maxParallelism: 10,
|
|
47
|
-
logLevel: "
|
|
47
|
+
logLevel: "WARN",
|
|
48
48
|
},
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -63,7 +63,7 @@ describe("lib", () => {
|
|
|
63
63
|
runAt: Date.now(),
|
|
64
64
|
config: {
|
|
65
65
|
maxParallelism: 101, // More than MAX_POSSIBLE_PARALLELISM
|
|
66
|
-
logLevel: "
|
|
66
|
+
logLevel: "WARN",
|
|
67
67
|
},
|
|
68
68
|
})
|
|
69
69
|
).rejects.toThrow("maxParallelism must be <= 100");
|
|
@@ -79,7 +79,7 @@ describe("lib", () => {
|
|
|
79
79
|
runAt: Date.now(),
|
|
80
80
|
config: {
|
|
81
81
|
maxParallelism: 0, // Less than minimum
|
|
82
|
-
logLevel: "
|
|
82
|
+
logLevel: "WARN",
|
|
83
83
|
},
|
|
84
84
|
})
|
|
85
85
|
).rejects.toThrow("maxParallelism must be >= 1");
|
|
@@ -96,13 +96,13 @@ describe("lib", () => {
|
|
|
96
96
|
runAt: Date.now(),
|
|
97
97
|
config: {
|
|
98
98
|
maxParallelism: 10,
|
|
99
|
-
logLevel: "
|
|
99
|
+
logLevel: "WARN",
|
|
100
100
|
},
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
await t.mutation(api.lib.cancel, {
|
|
104
104
|
id,
|
|
105
|
-
logLevel: "
|
|
105
|
+
logLevel: "WARN",
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
// Verify a pending cancelation was created
|
|
@@ -124,20 +124,20 @@ describe("lib", () => {
|
|
|
124
124
|
runAt: Date.now(),
|
|
125
125
|
config: {
|
|
126
126
|
maxParallelism: 10,
|
|
127
|
-
logLevel: "
|
|
127
|
+
logLevel: "WARN",
|
|
128
128
|
},
|
|
129
129
|
});
|
|
130
130
|
|
|
131
131
|
// Cancel the first time
|
|
132
132
|
await t.mutation(api.lib.cancel, {
|
|
133
133
|
id,
|
|
134
|
-
logLevel: "
|
|
134
|
+
logLevel: "WARN",
|
|
135
135
|
});
|
|
136
136
|
|
|
137
137
|
// Cancel the second time
|
|
138
138
|
await t.mutation(api.lib.cancel, {
|
|
139
139
|
id,
|
|
140
|
-
logLevel: "
|
|
140
|
+
logLevel: "WARN",
|
|
141
141
|
});
|
|
142
142
|
|
|
143
143
|
// Verify only one pending cancelation was created
|
|
@@ -159,7 +159,7 @@ describe("lib", () => {
|
|
|
159
159
|
runAt: Date.now(),
|
|
160
160
|
config: {
|
|
161
161
|
maxParallelism: 10,
|
|
162
|
-
logLevel: "
|
|
162
|
+
logLevel: "WARN",
|
|
163
163
|
},
|
|
164
164
|
});
|
|
165
165
|
|
|
@@ -171,7 +171,7 @@ describe("lib", () => {
|
|
|
171
171
|
// Try to cancel the deleted work
|
|
172
172
|
await t.mutation(api.lib.cancel, {
|
|
173
173
|
id,
|
|
174
|
-
logLevel: "
|
|
174
|
+
logLevel: "WARN",
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
// Verify no pending cancelation was created
|
|
@@ -196,14 +196,14 @@ describe("lib", () => {
|
|
|
196
196
|
runAt: Date.now() + 5 * 60 * 1000,
|
|
197
197
|
config: {
|
|
198
198
|
maxParallelism: 10,
|
|
199
|
-
logLevel: "
|
|
199
|
+
logLevel: "WARN",
|
|
200
200
|
},
|
|
201
201
|
});
|
|
202
202
|
ids.push(id);
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
await t.mutation(api.lib.cancelAll, {
|
|
206
|
-
logLevel: "
|
|
206
|
+
logLevel: "WARN",
|
|
207
207
|
before: Date.now() + 1000,
|
|
208
208
|
});
|
|
209
209
|
|
|
@@ -231,13 +231,13 @@ describe("lib", () => {
|
|
|
231
231
|
runAt: Date.now(),
|
|
232
232
|
config: {
|
|
233
233
|
maxParallelism: 10,
|
|
234
|
-
logLevel: "
|
|
234
|
+
logLevel: "WARN",
|
|
235
235
|
},
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
await t.mutation(api.lib.cancelAll, {
|
|
240
|
-
logLevel: "
|
|
240
|
+
logLevel: "WARN",
|
|
241
241
|
before: Date.now() + 1000,
|
|
242
242
|
});
|
|
243
243
|
|
|
@@ -277,7 +277,7 @@ describe("lib", () => {
|
|
|
277
277
|
runAt: Date.now(),
|
|
278
278
|
config: {
|
|
279
279
|
maxParallelism: 10,
|
|
280
|
-
logLevel: "
|
|
280
|
+
logLevel: "WARN",
|
|
281
281
|
},
|
|
282
282
|
});
|
|
283
283
|
await t.run(async (ctx) => {
|
|
@@ -297,7 +297,7 @@ describe("lib", () => {
|
|
|
297
297
|
runAt: Date.now(),
|
|
298
298
|
config: {
|
|
299
299
|
maxParallelism: 10,
|
|
300
|
-
logLevel: "
|
|
300
|
+
logLevel: "WARN",
|
|
301
301
|
},
|
|
302
302
|
});
|
|
303
303
|
|
|
@@ -323,7 +323,7 @@ describe("lib", () => {
|
|
|
323
323
|
runAt: Date.now(),
|
|
324
324
|
config: {
|
|
325
325
|
maxParallelism: 10,
|
|
326
|
-
logLevel: "
|
|
326
|
+
logLevel: "WARN",
|
|
327
327
|
},
|
|
328
328
|
});
|
|
329
329
|
|
|
@@ -353,7 +353,7 @@ describe("lib", () => {
|
|
|
353
353
|
},
|
|
354
354
|
config: {
|
|
355
355
|
maxParallelism: 10,
|
|
356
|
-
logLevel: "
|
|
356
|
+
logLevel: "WARN",
|
|
357
357
|
},
|
|
358
358
|
});
|
|
359
359
|
|
|
@@ -386,7 +386,7 @@ describe("lib", () => {
|
|
|
386
386
|
runAt: Date.now(),
|
|
387
387
|
config: {
|
|
388
388
|
maxParallelism: 10,
|
|
389
|
-
logLevel: "
|
|
389
|
+
logLevel: "WARN",
|
|
390
390
|
},
|
|
391
391
|
});
|
|
392
392
|
|
|
@@ -419,7 +419,7 @@ describe("lib", () => {
|
|
|
419
419
|
runAt: Date.now(),
|
|
420
420
|
config: {
|
|
421
421
|
maxParallelism: 10,
|
|
422
|
-
logLevel: "
|
|
422
|
+
logLevel: "WARN",
|
|
423
423
|
},
|
|
424
424
|
});
|
|
425
425
|
|
package/src/component/lib.ts
CHANGED
|
@@ -8,12 +8,14 @@ import {
|
|
|
8
8
|
status as statusValidator,
|
|
9
9
|
toSegment,
|
|
10
10
|
boundScheduledTime,
|
|
11
|
+
max,
|
|
11
12
|
} from "./shared.js";
|
|
12
13
|
import { LogLevel, logLevel } from "./logging.js";
|
|
13
14
|
import { kickMainLoop } from "./kick.js";
|
|
14
15
|
import { api } from "./_generated/api.js";
|
|
15
16
|
import { createLogger } from "./logging.js";
|
|
16
17
|
import { Id } from "./_generated/dataModel.js";
|
|
18
|
+
import { recordEnqueued } from "./stats.js";
|
|
17
19
|
|
|
18
20
|
const MAX_POSSIBLE_PARALLELISM = 100;
|
|
19
21
|
|
|
@@ -45,10 +47,10 @@ export const enqueue = mutation({
|
|
|
45
47
|
});
|
|
46
48
|
await ctx.db.insert("pendingStart", {
|
|
47
49
|
workId,
|
|
48
|
-
segment: toSegment(runAt),
|
|
50
|
+
segment: max(toSegment(runAt), nextSegment()),
|
|
49
51
|
});
|
|
50
52
|
await kickMainLoop(ctx, "enqueue", config);
|
|
51
|
-
|
|
53
|
+
recordEnqueued(console, { workId, fnName: workArgs.fnName, runAt });
|
|
52
54
|
return workId;
|
|
53
55
|
},
|
|
54
56
|
});
|
package/src/component/logging.ts
CHANGED
|
@@ -53,9 +53,8 @@ export function createLogger(level?: LogLevel): Logger {
|
|
|
53
53
|
event: (event: string, payload: Record<string, unknown>) => {
|
|
54
54
|
if (levelIndex <= 1) {
|
|
55
55
|
const fullPayload = {
|
|
56
|
-
system: "idempotent-workpool-component",
|
|
57
56
|
event,
|
|
58
|
-
payload,
|
|
57
|
+
...payload,
|
|
59
58
|
};
|
|
60
59
|
console.info(JSON.stringify(fullPayload));
|
|
61
60
|
}
|