@convex-dev/workpool 0.1.3-alpha.0 → 0.2.0-alpha.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 +148 -17
- package/dist/commonjs/client/index.d.ts +123 -35
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +122 -15
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/client/utils.d.ts +16 -0
- package/dist/commonjs/client/utils.d.ts.map +1 -0
- package/dist/commonjs/client/utils.js +2 -0
- package/dist/commonjs/client/utils.js.map +1 -0
- package/dist/commonjs/component/complete.d.ts +89 -0
- package/dist/commonjs/component/complete.d.ts.map +1 -0
- package/dist/commonjs/component/complete.js +80 -0
- package/dist/commonjs/component/complete.js.map +1 -0
- package/dist/commonjs/component/convex.config.d.ts.map +1 -1
- package/dist/commonjs/component/convex.config.js +0 -2
- package/dist/commonjs/component/convex.config.js.map +1 -1
- package/dist/commonjs/component/kick.d.ts +9 -0
- package/dist/commonjs/component/kick.d.ts.map +1 -0
- package/dist/commonjs/component/kick.js +97 -0
- package/dist/commonjs/component/kick.js.map +1 -0
- package/dist/commonjs/component/lib.d.ts +23 -32
- package/dist/commonjs/component/lib.d.ts.map +1 -1
- package/dist/commonjs/component/lib.js +91 -563
- package/dist/commonjs/component/lib.js.map +1 -1
- package/dist/commonjs/component/logging.d.ts +6 -4
- package/dist/commonjs/component/logging.d.ts.map +1 -1
- package/dist/commonjs/component/logging.js +13 -2
- package/dist/commonjs/component/logging.js.map +1 -1
- package/dist/commonjs/component/loop.d.ts +13 -0
- package/dist/commonjs/component/loop.d.ts.map +1 -0
- package/dist/commonjs/component/loop.js +482 -0
- package/dist/commonjs/component/loop.js.map +1 -0
- package/dist/commonjs/component/recovery.d.ts +24 -0
- package/dist/commonjs/component/recovery.d.ts.map +1 -0
- package/dist/commonjs/component/recovery.js +94 -0
- package/dist/commonjs/component/recovery.js.map +1 -0
- package/dist/commonjs/component/schema.d.ts +167 -93
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +56 -65
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/shared.d.ts +138 -0
- package/dist/commonjs/component/shared.d.ts.map +1 -0
- package/dist/commonjs/component/shared.js +77 -0
- package/dist/commonjs/component/shared.js.map +1 -0
- package/dist/commonjs/component/stats.d.ts +5 -2
- package/dist/commonjs/component/stats.d.ts.map +1 -1
- package/dist/commonjs/component/stats.js +22 -3
- package/dist/commonjs/component/stats.js.map +1 -1
- package/dist/commonjs/component/worker.d.ts +15 -0
- package/dist/commonjs/component/worker.d.ts.map +1 -0
- package/dist/commonjs/component/worker.js +73 -0
- package/dist/commonjs/component/worker.js.map +1 -0
- package/dist/esm/client/index.d.ts +123 -35
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +122 -15
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/utils.d.ts +16 -0
- package/dist/esm/client/utils.d.ts.map +1 -0
- package/dist/esm/client/utils.js +2 -0
- package/dist/esm/client/utils.js.map +1 -0
- package/dist/esm/component/complete.d.ts +89 -0
- package/dist/esm/component/complete.d.ts.map +1 -0
- package/dist/esm/component/complete.js +80 -0
- package/dist/esm/component/complete.js.map +1 -0
- package/dist/esm/component/convex.config.d.ts.map +1 -1
- package/dist/esm/component/convex.config.js +0 -2
- package/dist/esm/component/convex.config.js.map +1 -1
- package/dist/esm/component/kick.d.ts +9 -0
- package/dist/esm/component/kick.d.ts.map +1 -0
- package/dist/esm/component/kick.js +97 -0
- package/dist/esm/component/kick.js.map +1 -0
- package/dist/esm/component/lib.d.ts +23 -32
- package/dist/esm/component/lib.d.ts.map +1 -1
- package/dist/esm/component/lib.js +91 -563
- package/dist/esm/component/lib.js.map +1 -1
- package/dist/esm/component/logging.d.ts +6 -4
- package/dist/esm/component/logging.d.ts.map +1 -1
- package/dist/esm/component/logging.js +13 -2
- package/dist/esm/component/logging.js.map +1 -1
- package/dist/esm/component/loop.d.ts +13 -0
- package/dist/esm/component/loop.d.ts.map +1 -0
- package/dist/esm/component/loop.js +482 -0
- package/dist/esm/component/loop.js.map +1 -0
- package/dist/esm/component/recovery.d.ts +24 -0
- package/dist/esm/component/recovery.d.ts.map +1 -0
- package/dist/esm/component/recovery.js +94 -0
- package/dist/esm/component/recovery.js.map +1 -0
- package/dist/esm/component/schema.d.ts +167 -93
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +56 -65
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/shared.d.ts +138 -0
- package/dist/esm/component/shared.d.ts.map +1 -0
- package/dist/esm/component/shared.js +77 -0
- package/dist/esm/component/shared.js.map +1 -0
- package/dist/esm/component/stats.d.ts +5 -2
- package/dist/esm/component/stats.d.ts.map +1 -1
- package/dist/esm/component/stats.js +22 -3
- package/dist/esm/component/stats.js.map +1 -1
- package/dist/esm/component/worker.d.ts +15 -0
- package/dist/esm/component/worker.d.ts.map +1 -0
- package/dist/esm/component/worker.js +73 -0
- package/dist/esm/component/worker.js.map +1 -0
- package/package.json +6 -5
- package/src/client/index.ts +231 -70
- package/src/client/utils.ts +45 -0
- package/src/component/README.md +73 -0
- package/src/component/_generated/api.d.ts +38 -66
- package/src/component/complete.test.ts +508 -0
- package/src/component/complete.ts +98 -0
- package/src/component/convex.config.ts +0 -3
- package/src/component/kick.test.ts +285 -0
- package/src/component/kick.ts +118 -0
- package/src/component/lib.test.ts +448 -0
- package/src/component/lib.ts +105 -667
- package/src/component/logging.ts +24 -10
- package/src/component/loop.test.ts +1204 -0
- package/src/component/loop.ts +637 -0
- package/src/component/recovery.test.ts +541 -0
- package/src/component/recovery.ts +96 -0
- package/src/component/schema.ts +61 -77
- package/src/component/setup.test.ts +5 -0
- package/src/component/shared.ts +141 -0
- package/src/component/stats.ts +24 -6
- package/src/component/worker.ts +81 -0
package/README.md
CHANGED
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
This Convex component pools actions and mutations to restrict parallel requests.
|
|
8
8
|
|
|
9
|
+
- Configure multiple pools with different parallelism.
|
|
10
|
+
- Retry failed actions (with backoff and jitter) for
|
|
11
|
+
[idempotent actions](#idempotency), fully configurable (respecting parallelism).
|
|
12
|
+
- An `onComplete` callback so you can build durable, reliable workflows. Called
|
|
13
|
+
when the work is finished, whether it succeeded, failed, or was canceled.
|
|
14
|
+
|
|
15
|
+
## Use cases
|
|
16
|
+
|
|
17
|
+
### Separating and throttling async workloads
|
|
18
|
+
|
|
9
19
|
Suppose you have some important async work, like sending verification emails,
|
|
10
20
|
and some less important async work, like scraping data from an API. If all of
|
|
11
21
|
these are scheduled with `ctx.scheduler.runAfter`, they'll compete with each
|
|
@@ -16,13 +26,14 @@ To resolve this problem, you can separate work into different pools.
|
|
|
16
26
|
|
|
17
27
|
```ts
|
|
18
28
|
const emailPool = new Workpool(components.emailWorkpool, {
|
|
19
|
-
maxParallelism:
|
|
29
|
+
maxParallelism: 10,
|
|
20
30
|
});
|
|
21
31
|
const scrapePool = new Workpool(components.scrapeWorkpool, {
|
|
22
|
-
maxParallelism:
|
|
32
|
+
maxParallelism: 5,
|
|
23
33
|
});
|
|
24
34
|
|
|
25
|
-
export const
|
|
35
|
+
export const userSignUp = mutation({
|
|
36
|
+
args: {...},
|
|
26
37
|
handler: async (ctx, args) => {
|
|
27
38
|
const userId = await ctx.db.insert("users", args);
|
|
28
39
|
await emailPool.enqueueAction(ctx, internal.auth.sendEmailVerification, {
|
|
@@ -40,6 +51,95 @@ export const downloadLatestWeather = mutation({
|
|
|
40
51
|
});
|
|
41
52
|
```
|
|
42
53
|
|
|
54
|
+
### Durable, reliable workflows meet workpool
|
|
55
|
+
|
|
56
|
+
#### Retry management
|
|
57
|
+
|
|
58
|
+
Imagine that the payment processor is a 3rd party API, and they temporarily have an
|
|
59
|
+
outage. Now imagine you implement your own action retrying logic for your busy app.
|
|
60
|
+
You'll find very quickly that your entire backend is overwhelmed with retrying actions.
|
|
61
|
+
This could bog down live traffic with background work, and/or cause you to exceed
|
|
62
|
+
rate limits with the payment provider.
|
|
63
|
+
|
|
64
|
+
Creating an upper bound on how much work will be done in parallel is a good way to
|
|
65
|
+
mitigate this risk. Actions that are currently backing off awaiting retry will not tie
|
|
66
|
+
up a thread in the workpool.
|
|
67
|
+
|
|
68
|
+
#### Completion handling
|
|
69
|
+
|
|
70
|
+
By handing off asynchronous work, it will be guaranteed to run, and with retries
|
|
71
|
+
you can account for temporary failures, while avoiding a "stampeding herd"
|
|
72
|
+
during third party outages.
|
|
73
|
+
|
|
74
|
+
With the `onComplete` callback, you can define how to proceed after each step,
|
|
75
|
+
whether that enqueues another job to the workpool, updates the database, etc.
|
|
76
|
+
It will always be called, whether the work was successful, failed, or was
|
|
77
|
+
canceled. See [below](#options-for-enqueueing-work) for more info.
|
|
78
|
+
|
|
79
|
+
Example:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const pool = new Workpool(components.emailWorkpool, {
|
|
83
|
+
retryActionsByDefault: true,
|
|
84
|
+
defaultRetryBehavior: { maxAttempts: 3, initialBackoffMs: 1000, base: 2 },
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
//...
|
|
88
|
+
|
|
89
|
+
await pool.enqueueAction(ctx, internal.email.send, args, {
|
|
90
|
+
onComplete: internal.email.emailSent,
|
|
91
|
+
context: { emailType, userId },
|
|
92
|
+
retry: false, // don't retry this action, as we can't guarantee idempotency.
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
export const emailSent = internalMutation({
|
|
96
|
+
args: {
|
|
97
|
+
workId: workIdValidator,
|
|
98
|
+
context: v.object({ emailType: v.string(), userId: v.id("users") }),
|
|
99
|
+
result: runResultValidator,
|
|
100
|
+
},
|
|
101
|
+
handler: async (ctx, args) => {
|
|
102
|
+
if (args.result.kind === "canceled") return;
|
|
103
|
+
await ctx.db.insert("userEmailLog", {
|
|
104
|
+
userId: args.context.userId,
|
|
105
|
+
emailType: args.context.emailType,
|
|
106
|
+
result: args.result.kind === "success" ? args.result.returnValue : null,
|
|
107
|
+
error: args.result.kind === "failed" ? args.result.error : null,
|
|
108
|
+
});
|
|
109
|
+
if (args.result.kind === "failed") {
|
|
110
|
+
await pool.enqueueAction(ctx, internal.email.checkResendStatus, args, {
|
|
111
|
+
retry: { maxAttempts: 10, initialBackoffMs: 250, base: 2 }, // custom
|
|
112
|
+
onComplete: internal.email.handleEmailStatus,
|
|
113
|
+
context: args.context,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### Idempotency?
|
|
121
|
+
|
|
122
|
+
Idempotent actions are actions that can be run multiple times safely. This typically
|
|
123
|
+
means they don't cause any side effects that would be a problem if executed twice or more.
|
|
124
|
+
|
|
125
|
+
As an example of an unsafe, non-idempotent action, consider an action that charges
|
|
126
|
+
a user's credit card without providing a unique transaction id to the payment
|
|
127
|
+
processor. The first time the action is run, imagine that the API call succeeds to the
|
|
128
|
+
payment provider, but then the action throws an exception before the transaction is marked
|
|
129
|
+
finished in our Convex database. If the action is run twice, the user may be
|
|
130
|
+
double charged for the transaction!
|
|
131
|
+
|
|
132
|
+
If we alter this action to provide a consistent transaction id to the payment provider, they
|
|
133
|
+
can simply NOOP the second payment attempt. The this makes the action idempotent, and
|
|
134
|
+
it can safely be retried.
|
|
135
|
+
|
|
136
|
+
If you're creating complex workflows with many steps involving 3rd party APIs:
|
|
137
|
+
|
|
138
|
+
1. You should ensure that each step is an idempotent Convex action.
|
|
139
|
+
2. You should use this component to manage these actions so it all just works!
|
|
140
|
+
|
|
141
|
+
### Optimize OCC errors
|
|
142
|
+
|
|
43
143
|
With limited parallelism, you can reduce
|
|
44
144
|
[OCC errors](https://docs.convex.dev/error#1)
|
|
45
145
|
from mutations that read and write the same data.
|
|
@@ -133,6 +233,41 @@ await pool.cancel(id);
|
|
|
133
233
|
|
|
134
234
|
See more example usage in [example.ts](./example/convex/example.ts).
|
|
135
235
|
|
|
236
|
+
### Configuring the Workpool
|
|
237
|
+
|
|
238
|
+
Check out the [docstrings](./src/client/index.ts), but notable options include:
|
|
239
|
+
|
|
240
|
+
- `maxParallelism`: How many actions/mutations can run at once within this pool.
|
|
241
|
+
- `retryActionsByDefault`: Whether to retry actions that fail by default.
|
|
242
|
+
- `defaultRetryBehavior`: The default retry behavior for enqueued actions.
|
|
243
|
+
|
|
244
|
+
You can override the retry behavior per-call with the `retry` option.
|
|
245
|
+
|
|
246
|
+
### Options for enqueueing work
|
|
247
|
+
|
|
248
|
+
See the [docstrings](./src/client/index.ts) for more details, but notable options include:
|
|
249
|
+
|
|
250
|
+
- `retry`: Whether to retry the action if it fails. Overrides defaults.
|
|
251
|
+
If it's set to `true`, it will use the `defaultRetryBehavior`.
|
|
252
|
+
If it's set to a custom config, it will use that (and do retries).
|
|
253
|
+
- `onComplete`: A mutation to run after the function finishes.
|
|
254
|
+
- `context`: Any data you want to pass to the `onComplete` mutation.
|
|
255
|
+
- `runAt` and `runAfter`: Similar to `ctx.scheduler.run*`, allows you to
|
|
256
|
+
schedule the work to run later. By default it's immediate.
|
|
257
|
+
|
|
258
|
+
### Retry behavior
|
|
259
|
+
|
|
260
|
+
The retry options work like this:
|
|
261
|
+
|
|
262
|
+
- The first request runs as it's scheduled.
|
|
263
|
+
- If it fails, it will wait _around_ `initialBackoffMs` and then try again.
|
|
264
|
+
- Each subsequent retry waits `initialBackoffMs * base^<retryNumber - 1>`.
|
|
265
|
+
- The standard base is 2.
|
|
266
|
+
- The actual wait time uses "jitter" to avoid all retries happening at once,
|
|
267
|
+
if they all failed at the same time.
|
|
268
|
+
|
|
269
|
+
You can override the retry behavior per-call with the `retry` option.
|
|
270
|
+
|
|
136
271
|
## Optimizations with and without Workpool
|
|
137
272
|
|
|
138
273
|
The benefit of Workpool is that it won't fall over if there are many jobs
|
|
@@ -168,23 +303,19 @@ You can read the status of a function by calling `pool.status(id)`.
|
|
|
168
303
|
|
|
169
304
|
The status will be one of:
|
|
170
305
|
|
|
171
|
-
- `{ kind: "pending" }`: The function has not started yet.
|
|
172
|
-
- `{ kind: "
|
|
173
|
-
- `{ kind: "
|
|
174
|
-
finished.
|
|
175
|
-
|
|
176
|
-
The `CompletionStatus` type is one of:
|
|
177
|
-
|
|
178
|
-
- `"success"`: The function completed successfully.
|
|
179
|
-
- `"error"`: The function threw an error.
|
|
180
|
-
- `"canceled"`: The function was canceled.
|
|
181
|
-
- `"timeout"`: The function timed out.
|
|
306
|
+
- `{ kind: "pending"; previousAttempts: number }`: The function has not started yet.
|
|
307
|
+
- `{ kind: "running"; previousAttempts: number }`: The function is currently running.
|
|
308
|
+
- `{ kind: "finished" }`: The function has succeeded, failed, or been canceled.
|
|
182
309
|
|
|
183
310
|
## Canceling work
|
|
184
311
|
|
|
185
|
-
You can cancel work by calling `pool.cancel(id)
|
|
312
|
+
You can cancel work by calling `pool.cancel(id)` or all of them with
|
|
313
|
+
`pool.cancelAll()`.
|
|
186
314
|
|
|
187
|
-
This will
|
|
188
|
-
If
|
|
315
|
+
This will avoid starting or retrying, but will not stop in-progress work.
|
|
189
316
|
|
|
190
317
|
<!-- END: Include on https://convex.dev/components -->
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
```
|
|
@@ -1,53 +1,141 @@
|
|
|
1
|
-
import { DefaultFunctionArgs,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export type
|
|
1
|
+
import { DefaultFunctionArgs, FunctionReference, FunctionVisibility } from "convex/server";
|
|
2
|
+
import { VString } from "convex/values";
|
|
3
|
+
import { Mounts } from "../component/_generated/api.js";
|
|
4
|
+
import { runResult as runResultValidator, RunResult, type RetryBehavior, Status } from "../component/shared.js";
|
|
5
|
+
import { type LogLevel } from "../component/logging.js";
|
|
6
|
+
import { RunMutationCtx, RunQueryCtx, UseApi } from "./utils.js";
|
|
7
|
+
export { runResultValidator, type RunResult };
|
|
8
|
+
export declare const DEFAULT_RETRY_BEHAVIOR: RetryBehavior;
|
|
9
|
+
export type WorkId = string & {
|
|
10
|
+
__isWorkId: true;
|
|
11
|
+
};
|
|
12
|
+
export declare const workIdValidator: VString<WorkId, "required">;
|
|
8
13
|
export declare class Workpool {
|
|
9
14
|
private component;
|
|
10
15
|
private options;
|
|
11
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Initializes a Workpool.
|
|
18
|
+
*
|
|
19
|
+
* Note: if you want different pools, you need to *create different instances*
|
|
20
|
+
* of Workpool in convex.config.ts. It isn't sufficient to have different
|
|
21
|
+
* instances of this class.
|
|
22
|
+
*
|
|
23
|
+
* @param component - The component to use, like `components.workpool` from
|
|
24
|
+
* `./_generated/api.ts`.
|
|
25
|
+
* @param options - The options for the Workpool.
|
|
26
|
+
*/
|
|
27
|
+
constructor(component: UseApi<Mounts>, // UseApi<api> for jump to definition
|
|
28
|
+
options: {
|
|
12
29
|
/** How many actions/mutations can be running at once within this pool.
|
|
13
30
|
* Min 1, Max 300.
|
|
14
31
|
*/
|
|
15
|
-
maxParallelism
|
|
16
|
-
/** How much to log.
|
|
17
|
-
*
|
|
32
|
+
maxParallelism?: number;
|
|
33
|
+
/** How much to log. This is updated on each call to `enqueue*`,
|
|
34
|
+
* `status`, or `cancel*`.
|
|
35
|
+
* Default is WARN.
|
|
18
36
|
* With INFO, you can see events for started and completed work, which can
|
|
19
|
-
* be parsed.
|
|
37
|
+
* be parsed by tools like [Axiom](https://axiom.co) for monitoring.
|
|
20
38
|
* With DEBUG, you can see timers and internal events for work being
|
|
21
39
|
* scheduled.
|
|
22
40
|
*/
|
|
23
41
|
logLevel?: LogLevel;
|
|
24
|
-
/**
|
|
25
|
-
|
|
42
|
+
/** Default retry behavior for enqueued actions. */
|
|
43
|
+
defaultRetryBehavior?: RetryBehavior;
|
|
44
|
+
/** Whether to retry actions that fail by default. Default: false.
|
|
45
|
+
* NOTE: Only do this if your actions are idempotent.
|
|
46
|
+
* See the docs (README.md) for more details.
|
|
26
47
|
*/
|
|
27
|
-
|
|
48
|
+
retryActionsByDefault?: boolean;
|
|
28
49
|
});
|
|
29
|
-
|
|
30
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Enqueues an action to be run.
|
|
52
|
+
*
|
|
53
|
+
* @param ctx - The mutation or action context that can call ctx.runMutation.
|
|
54
|
+
* @param fn - The action to run, like `internal.example.myAction`.
|
|
55
|
+
* @param fnArgs - The arguments to pass to the action.
|
|
56
|
+
* @param options - The options for the action to specify retry behavior,
|
|
57
|
+
* onComplete handling, and scheduling via `runAt` or `runAfter`.
|
|
58
|
+
* @returns The ID of the work that was enqueued.
|
|
59
|
+
*/
|
|
60
|
+
enqueueAction<Args extends DefaultFunctionArgs, ReturnType>(ctx: RunMutationCtx, fn: FunctionReference<"action", FunctionVisibility, Args, ReturnType>, fnArgs: Args, options?: {
|
|
61
|
+
/** Whether to retry the action if it fails.
|
|
62
|
+
* If true, it will use the default retry behavior.
|
|
63
|
+
* If custom behavior is provided, it will retry using that behavior.
|
|
64
|
+
* If unset, it will use the Workpool's configured default.
|
|
65
|
+
*/
|
|
66
|
+
retry?: boolean | RetryBehavior;
|
|
67
|
+
} & CallbackOptions & SchedulerOptions): Promise<WorkId>;
|
|
68
|
+
/**
|
|
69
|
+
* Enqueues a mutation to be run.
|
|
70
|
+
*
|
|
71
|
+
* Note: mutations are not retried by the workpool. Convex automatically
|
|
72
|
+
* retries them on database conflicts and transient failures.
|
|
73
|
+
* Because they're deterministic, external retries don't provide any benefit.
|
|
74
|
+
*
|
|
75
|
+
* @param ctx - The mutation or action context that can call ctx.runMutation.
|
|
76
|
+
* @param fn - The mutation to run, like `internal.example.myMutation`.
|
|
77
|
+
* @param fnArgs - The arguments to pass to the mutation.
|
|
78
|
+
* @param options - The options for the mutation to specify onComplete handling
|
|
79
|
+
* and scheduling via `runAt` or `runAfter`.
|
|
80
|
+
*/
|
|
81
|
+
enqueueMutation<Args extends DefaultFunctionArgs, ReturnType>(ctx: RunMutationCtx, fn: FunctionReference<"mutation", FunctionVisibility, Args, ReturnType>, fnArgs: Args, options?: CallbackOptions & SchedulerOptions): Promise<WorkId>;
|
|
31
82
|
cancel(ctx: RunMutationCtx, id: WorkId): Promise<void>;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
} | {
|
|
35
|
-
kind: "inProgress";
|
|
36
|
-
} | {
|
|
37
|
-
kind: "completed";
|
|
38
|
-
completionStatus: CompletionStatus;
|
|
39
|
-
}>;
|
|
83
|
+
cancelAll(ctx: RunMutationCtx): Promise<void>;
|
|
84
|
+
status(ctx: RunQueryCtx, id: WorkId): Promise<Status>;
|
|
40
85
|
}
|
|
41
|
-
type
|
|
42
|
-
|
|
86
|
+
export type SchedulerOptions = {
|
|
87
|
+
/**
|
|
88
|
+
* The time (ms since epoch) to run the action at.
|
|
89
|
+
* If not provided, the action will be run as soon as possible.
|
|
90
|
+
* Note: this is advisory only. It may run later.
|
|
91
|
+
*/
|
|
92
|
+
runAt?: number;
|
|
93
|
+
} | {
|
|
94
|
+
/**
|
|
95
|
+
* The number of milliseconds to run the action after.
|
|
96
|
+
* If not provided, the action will be run as soon as possible.
|
|
97
|
+
* Note: this is advisory only. It may run later.
|
|
98
|
+
*/
|
|
99
|
+
runAfter?: number;
|
|
100
|
+
};
|
|
101
|
+
export type CallbackOptions = {
|
|
102
|
+
/**
|
|
103
|
+
* A mutation to run after the function succeeds, fails, or is canceled.
|
|
104
|
+
* The context type is for your use, feel free to provide a validator for it.
|
|
105
|
+
* e.g.
|
|
106
|
+
* ```ts
|
|
107
|
+
* export const completion = internalMutation({
|
|
108
|
+
* args: {
|
|
109
|
+
* workId: workIdValidator,
|
|
110
|
+
* context: v.any(),
|
|
111
|
+
* result: runResult,
|
|
112
|
+
* },
|
|
113
|
+
* handler: async (ctx, args) => {
|
|
114
|
+
* console.log(args.result, "Got Context back -> ", args.context, Date.now() - args.context);
|
|
115
|
+
* },
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
onComplete?: FunctionReference<"mutation", FunctionVisibility, OnCompleteArgs> | null;
|
|
120
|
+
/**
|
|
121
|
+
* A context object to pass to the `onComplete` mutation.
|
|
122
|
+
* Useful for passing data from the enqueue site to the onComplete site.
|
|
123
|
+
*/
|
|
124
|
+
context?: unknown;
|
|
43
125
|
};
|
|
44
|
-
type
|
|
45
|
-
|
|
126
|
+
export type OnCompleteArgs = {
|
|
127
|
+
/**
|
|
128
|
+
* The ID of the work that completed.
|
|
129
|
+
*/
|
|
130
|
+
workId: WorkId;
|
|
131
|
+
/**
|
|
132
|
+
* The context object passed when enqueuing the work.
|
|
133
|
+
* Useful for passing data from the enqueue site to the onComplete site.
|
|
134
|
+
*/
|
|
135
|
+
context: unknown;
|
|
136
|
+
/**
|
|
137
|
+
* The result of the run that completed.
|
|
138
|
+
*/
|
|
139
|
+
result: RunResult;
|
|
46
140
|
};
|
|
47
|
-
export type OpaqueIds<T> = T extends GenericId<infer _T> ? string : T extends (infer U)[] ? OpaqueIds<U>[] : T extends object ? {
|
|
48
|
-
[K in keyof T]: OpaqueIds<T[K]>;
|
|
49
|
-
} : T;
|
|
50
|
-
export type UseApi<API> = Expand<{
|
|
51
|
-
[mod in keyof API]: API[mod] extends FunctionReference<infer FType, "public", infer FArgs, infer FReturnType, infer FComponentPath> ? FunctionReference<FType, "internal", OpaqueIds<FArgs>, OpaqueIds<FReturnType>, FComponentPath> : UseApi<API[mod]>;
|
|
52
|
-
}>;
|
|
53
141
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,mBAAmB,EACnB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,40 +1,147 @@
|
|
|
1
1
|
import { createFunctionHandle, getFunctionName, } from "convex/server";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
import { runResult as runResultValidator, } from "../component/shared.js";
|
|
4
|
+
import { logLevel } from "../component/logging.js";
|
|
5
|
+
import { DEFAULT_LOG_LEVEL } from "../component/logging.js";
|
|
6
|
+
import { DEFAULT_MAX_PARALLELISM } from "../component/kick.js";
|
|
7
|
+
export { runResultValidator };
|
|
8
|
+
// Attempts will run with delay [0, 250, 500, 1000, 2000] (ms)
|
|
9
|
+
export const DEFAULT_RETRY_BEHAVIOR = {
|
|
10
|
+
maxAttempts: 5,
|
|
11
|
+
initialBackoffMs: 250,
|
|
12
|
+
base: 2,
|
|
13
|
+
};
|
|
14
|
+
export const workIdValidator = v.string();
|
|
4
15
|
export class Workpool {
|
|
5
16
|
component;
|
|
6
17
|
options;
|
|
7
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Initializes a Workpool.
|
|
20
|
+
*
|
|
21
|
+
* Note: if you want different pools, you need to *create different instances*
|
|
22
|
+
* of Workpool in convex.config.ts. It isn't sufficient to have different
|
|
23
|
+
* instances of this class.
|
|
24
|
+
*
|
|
25
|
+
* @param component - The component to use, like `components.workpool` from
|
|
26
|
+
* `./_generated/api.ts`.
|
|
27
|
+
* @param options - The options for the Workpool.
|
|
28
|
+
*/
|
|
29
|
+
constructor(component, // UseApi<api> for jump to definition
|
|
30
|
+
options) {
|
|
8
31
|
this.component = component;
|
|
9
32
|
this.options = options;
|
|
10
33
|
}
|
|
11
|
-
|
|
12
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Enqueues an action to be run.
|
|
36
|
+
*
|
|
37
|
+
* @param ctx - The mutation or action context that can call ctx.runMutation.
|
|
38
|
+
* @param fn - The action to run, like `internal.example.myAction`.
|
|
39
|
+
* @param fnArgs - The arguments to pass to the action.
|
|
40
|
+
* @param options - The options for the action to specify retry behavior,
|
|
41
|
+
* onComplete handling, and scheduling via `runAt` or `runAfter`.
|
|
42
|
+
* @returns The ID of the work that was enqueued.
|
|
43
|
+
*/
|
|
44
|
+
async enqueueAction(ctx, fn, fnArgs, options) {
|
|
45
|
+
const retryBehavior = getRetryBehavior(this.options.defaultRetryBehavior, this.options.retryActionsByDefault, options?.retry);
|
|
46
|
+
const onComplete = options?.onComplete
|
|
47
|
+
? {
|
|
48
|
+
fnHandle: await createFunctionHandle(options.onComplete),
|
|
49
|
+
context: options.context,
|
|
50
|
+
}
|
|
51
|
+
: undefined;
|
|
13
52
|
const id = await ctx.runMutation(this.component.lib.enqueue, {
|
|
14
|
-
|
|
15
|
-
fnName: getFunctionName(fn),
|
|
53
|
+
...(await defaultEnqueueArgs(fn, this.options)),
|
|
16
54
|
fnArgs,
|
|
17
55
|
fnType: "action",
|
|
18
|
-
|
|
56
|
+
runAt: getRunAt(options),
|
|
57
|
+
onComplete,
|
|
58
|
+
retryBehavior,
|
|
19
59
|
});
|
|
20
60
|
return id;
|
|
21
61
|
}
|
|
22
|
-
|
|
23
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Enqueues a mutation to be run.
|
|
64
|
+
*
|
|
65
|
+
* Note: mutations are not retried by the workpool. Convex automatically
|
|
66
|
+
* retries them on database conflicts and transient failures.
|
|
67
|
+
* Because they're deterministic, external retries don't provide any benefit.
|
|
68
|
+
*
|
|
69
|
+
* @param ctx - The mutation or action context that can call ctx.runMutation.
|
|
70
|
+
* @param fn - The mutation to run, like `internal.example.myMutation`.
|
|
71
|
+
* @param fnArgs - The arguments to pass to the mutation.
|
|
72
|
+
* @param options - The options for the mutation to specify onComplete handling
|
|
73
|
+
* and scheduling via `runAt` or `runAfter`.
|
|
74
|
+
*/
|
|
75
|
+
async enqueueMutation(ctx, fn, fnArgs, options) {
|
|
24
76
|
const id = await ctx.runMutation(this.component.lib.enqueue, {
|
|
25
|
-
|
|
26
|
-
fnName: getFunctionName(fn),
|
|
77
|
+
...(await defaultEnqueueArgs(fn, this.options)),
|
|
27
78
|
fnArgs,
|
|
28
79
|
fnType: "mutation",
|
|
29
|
-
|
|
80
|
+
runAt: getRunAt(options),
|
|
30
81
|
});
|
|
31
82
|
return id;
|
|
32
83
|
}
|
|
33
84
|
async cancel(ctx, id) {
|
|
34
|
-
await ctx.runMutation(this.component.lib.cancel, {
|
|
85
|
+
await ctx.runMutation(this.component.lib.cancel, {
|
|
86
|
+
id,
|
|
87
|
+
logLevel: this.options.logLevel ?? getDefaultLogLevel(),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async cancelAll(ctx) {
|
|
91
|
+
await ctx.runMutation(this.component.lib.cancelAll, {
|
|
92
|
+
logLevel: this.options.logLevel ?? getDefaultLogLevel(),
|
|
93
|
+
});
|
|
35
94
|
}
|
|
36
95
|
async status(ctx, id) {
|
|
37
|
-
return
|
|
96
|
+
return ctx.runQuery(this.component.lib.status, { id });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function getRetryBehavior(defaultRetryBehavior, retryActionsByDefault, retryOverride) {
|
|
100
|
+
const defaultRetry = defaultRetryBehavior ?? DEFAULT_RETRY_BEHAVIOR;
|
|
101
|
+
const retryByDefault = retryActionsByDefault ?? false;
|
|
102
|
+
if (retryOverride === true) {
|
|
103
|
+
return defaultRetry;
|
|
104
|
+
}
|
|
105
|
+
if (retryOverride === false) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
return retryOverride ?? (retryByDefault ? defaultRetry : undefined);
|
|
109
|
+
}
|
|
110
|
+
async function defaultEnqueueArgs(fn, { logLevel, maxParallelism }) {
|
|
111
|
+
return {
|
|
112
|
+
fnHandle: await createFunctionHandle(fn),
|
|
113
|
+
fnName: getFunctionName(fn),
|
|
114
|
+
config: {
|
|
115
|
+
logLevel: logLevel ?? getDefaultLogLevel(),
|
|
116
|
+
maxParallelism: maxParallelism ?? DEFAULT_MAX_PARALLELISM,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// ensure OnCompleteArgs satisfies SharedOnCompleteArgs
|
|
121
|
+
const _ = {};
|
|
122
|
+
function getRunAt(options) {
|
|
123
|
+
if (!options) {
|
|
124
|
+
return Date.now();
|
|
125
|
+
}
|
|
126
|
+
if ("runAt" in options && options.runAt !== undefined) {
|
|
127
|
+
return options.runAt;
|
|
128
|
+
}
|
|
129
|
+
if ("runAfter" in options && options.runAfter !== undefined) {
|
|
130
|
+
return Date.now() + options.runAfter;
|
|
131
|
+
}
|
|
132
|
+
return Date.now();
|
|
133
|
+
}
|
|
134
|
+
function getDefaultLogLevel() {
|
|
135
|
+
if (process.env.WORKPOOL_LOG_LEVEL) {
|
|
136
|
+
if (!logLevel.members
|
|
137
|
+
.map((m) => m.value)
|
|
138
|
+
.includes(process.env.WORKPOOL_LOG_LEVEL)) {
|
|
139
|
+
console.warn(`Invalid log level (${process.env.WORKPOOL_LOG_LEVEL}), defaulting to "INFO"`);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
return process.env.WORKPOOL_LOG_LEVEL;
|
|
143
|
+
}
|
|
38
144
|
}
|
|
145
|
+
return DEFAULT_LOG_LEVEL;
|
|
39
146
|
}
|
|
40
147
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Expand, FunctionReference, GenericMutationCtx, GenericQueryCtx } from "convex/server";
|
|
2
|
+
import { GenericId } from "convex/values";
|
|
3
|
+
import { GenericDataModel } from "convex/server";
|
|
4
|
+
export type RunQueryCtx = {
|
|
5
|
+
runQuery: GenericQueryCtx<GenericDataModel>["runQuery"];
|
|
6
|
+
};
|
|
7
|
+
export type RunMutationCtx = {
|
|
8
|
+
runMutation: GenericMutationCtx<GenericDataModel>["runMutation"];
|
|
9
|
+
};
|
|
10
|
+
export type OpaqueIds<T> = T extends GenericId<infer _T> ? string : T extends (infer U)[] ? OpaqueIds<U>[] : T extends object ? {
|
|
11
|
+
[K in keyof T]: OpaqueIds<T[K]>;
|
|
12
|
+
} : T;
|
|
13
|
+
export type UseApi<API> = Expand<{
|
|
14
|
+
[mod in keyof API]: API[mod] extends FunctionReference<infer FType, "public", infer FArgs, infer FReturnType, infer FComponentPath> ? FunctionReference<FType, "internal", OpaqueIds<FArgs>, OpaqueIds<FReturnType>, FComponentPath> : UseApi<API[mod]>;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/client/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAIjD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,eAAe,CAAC,gBAAgB,CAAC,CAAC,UAAU,CAAC,CAAC;CACzD,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,CAAC,aAAa,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,IACrB,CAAC,SAAS,SAAS,CAAC,MAAM,EAAE,CAAC,GACzB,MAAM,GACN,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GACnB,SAAS,CAAC,CAAC,CAAC,EAAE,GACd,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GACnC,CAAC,CAAC;AAEZ,MAAM,MAAM,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC;KAC9B,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,iBAAiB,CACpD,MAAM,KAAK,EACX,QAAQ,EACR,MAAM,KAAK,EACX,MAAM,WAAW,EACjB,MAAM,cAAc,CACrB,GACG,iBAAiB,CACf,KAAK,EACL,UAAU,EACV,SAAS,CAAC,KAAK,CAAC,EAChB,SAAS,CAAC,WAAW,CAAC,EACtB,cAAc,CACf,GACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACrB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/client/utils.ts"],"names":[],"mappings":""}
|