convex-batch-processor 0.5.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/LICENSE +21 -0
- package/README.md +395 -0
- package/dist/client/index.d.ts +212 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +78 -0
- package/dist/client/index.js.map +1 -0
- package/dist/component/_generated/api.d.ts +34 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +80 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +4 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/lib.d.ts +351 -0
- package/dist/component/lib.d.ts.map +1 -0
- package/dist/component/lib.js +879 -0
- package/dist/component/lib.js.map +1 -0
- package/dist/component/schema.d.ts +118 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +61 -0
- package/dist/component/schema.js.map +1 -0
- package/package.json +63 -0
- package/src/client/index.test.ts +123 -0
- package/src/client/index.ts +336 -0
- package/src/component/_generated/api.ts +50 -0
- package/src/component/_generated/component.ts +140 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/convex.config.ts +4 -0
- package/src/component/lib.ts +1082 -0
- package/src/component/schema.ts +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Blocksight
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# convex-batch-processor
|
|
2
|
+
|
|
3
|
+
A Convex component for batch processing:
|
|
4
|
+
|
|
5
|
+
1. **Batch Accumulator** - Collect items and flush when reaching size threshold or time interval
|
|
6
|
+
2. **Table Iterator** - Process large tables in controlled batch sizes with pause/resume support
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install convex-batch-processor
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
Add the component to your Convex app:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// convex/convex.config.ts
|
|
20
|
+
import { defineApp } from "convex/server";
|
|
21
|
+
import batchProcessor from "convex-batch-processor/convex.config";
|
|
22
|
+
|
|
23
|
+
const app = defineApp();
|
|
24
|
+
app.use(batchProcessor);
|
|
25
|
+
|
|
26
|
+
export default app;
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### Batch Accumulator
|
|
32
|
+
|
|
33
|
+
The batch accumulator collects items and flushes them based on:
|
|
34
|
+
- **Time interval**: Flush automatically after `flushIntervalMs` (primary trigger for high-throughput small items)
|
|
35
|
+
- **Size threshold**: Immediate flush when a single call adds `>= maxBatchSize` items
|
|
36
|
+
- **Manual trigger**: Force flush via API call
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { mutation, internalAction } from "./_generated/server";
|
|
40
|
+
import { internal, components } from "./_generated/api";
|
|
41
|
+
import { BatchProcessor } from "convex-batch-processor";
|
|
42
|
+
import { v } from "convex/values";
|
|
43
|
+
|
|
44
|
+
// Define the event schema
|
|
45
|
+
const analyticsEventValidator = v.object({
|
|
46
|
+
eventName: v.string(),
|
|
47
|
+
properties: v.optional(v.record(v.string(), v.string())),
|
|
48
|
+
timestamp: v.number(),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
type AnalyticsEvent = typeof analyticsEventValidator.type;
|
|
52
|
+
|
|
53
|
+
// Create a batch processor with config
|
|
54
|
+
// Note: Explicit type annotation is required when the file also exports Convex functions
|
|
55
|
+
const batchProcessor: BatchProcessor<AnalyticsEvent> = new BatchProcessor(components.batchProcessor, {
|
|
56
|
+
maxBatchSize: 100,
|
|
57
|
+
flushIntervalMs: 30000,
|
|
58
|
+
processBatch: internal.analytics.processEventsBatch,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Define the batch processor (must be an action)
|
|
62
|
+
export const processEventsBatch = internalAction({
|
|
63
|
+
args: { items: v.array(analyticsEventValidator) },
|
|
64
|
+
handler: async (ctx, { items }) => {
|
|
65
|
+
await fetch("https://api.analytics.com/batch", {
|
|
66
|
+
method: "POST",
|
|
67
|
+
body: JSON.stringify({ events: items }),
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Add items to a batch
|
|
73
|
+
export const trackEvent = mutation({
|
|
74
|
+
args: {
|
|
75
|
+
eventName: v.string(),
|
|
76
|
+
properties: v.optional(v.record(v.string(), v.string())),
|
|
77
|
+
},
|
|
78
|
+
handler: async (ctx, { eventName, properties }) => {
|
|
79
|
+
const event: AnalyticsEvent = { eventName, properties, timestamp: Date.now() };
|
|
80
|
+
|
|
81
|
+
return await batchProcessor.addItems(ctx, "analytics-events", [event]);
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Manual flush
|
|
86
|
+
await batchProcessor.flush(ctx, "analytics-events");
|
|
87
|
+
|
|
88
|
+
// Get batch status
|
|
89
|
+
await batchProcessor.getBatchStatus(ctx, "analytics-events");
|
|
90
|
+
|
|
91
|
+
// Get flush history
|
|
92
|
+
await batchProcessor.getFlushHistory(ctx, "analytics-events");
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The interval flush is scheduled automatically when the first item is added to a batch. No cron job is required.
|
|
96
|
+
|
|
97
|
+
### Table Iterator
|
|
98
|
+
|
|
99
|
+
The table iterator processes large datasets using a callback-based design:
|
|
100
|
+
|
|
101
|
+
1. **You provide**: `getNextBatch` (query) + `processBatch` (action)
|
|
102
|
+
2. **Component handles**: Scheduling, progress tracking, retries, pause/resume
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { mutation, query, internalQuery, internalAction, internalMutation } from "./_generated/server";
|
|
106
|
+
import { internal, components } from "./_generated/api";
|
|
107
|
+
import { BatchProcessor } from "convex-batch-processor";
|
|
108
|
+
import { v } from "convex/values";
|
|
109
|
+
|
|
110
|
+
// Define the user schema
|
|
111
|
+
const userValidator = v.object({
|
|
112
|
+
_id: v.id("users"),
|
|
113
|
+
_creationTime: v.number(),
|
|
114
|
+
name: v.string(),
|
|
115
|
+
email: v.string(),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
type User = typeof userValidator.type;
|
|
119
|
+
|
|
120
|
+
// For iterator-only usage, config is optional
|
|
121
|
+
const batchProcessor = new BatchProcessor(components.batchProcessor);
|
|
122
|
+
|
|
123
|
+
export const startMigration = mutation({
|
|
124
|
+
args: {},
|
|
125
|
+
handler: async (ctx) => {
|
|
126
|
+
const jobId = `migration-${Date.now()}`;
|
|
127
|
+
|
|
128
|
+
await batchProcessor.startIterator<User>(ctx, jobId, {
|
|
129
|
+
batchSize: 100,
|
|
130
|
+
delayBetweenBatchesMs: 100,
|
|
131
|
+
getNextBatch: internal.migrations.getNextBatch,
|
|
132
|
+
processBatch: internal.migrations.processBatch,
|
|
133
|
+
onComplete: internal.migrations.onComplete,
|
|
134
|
+
maxRetries: 5,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return { jobId };
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
export const getNextBatch = internalQuery({
|
|
142
|
+
args: {
|
|
143
|
+
cursor: v.optional(v.string()),
|
|
144
|
+
batchSize: v.number(),
|
|
145
|
+
},
|
|
146
|
+
handler: async (ctx, { cursor, batchSize }) => {
|
|
147
|
+
const results = await ctx.db
|
|
148
|
+
.query("users")
|
|
149
|
+
.paginate({ cursor: cursor ?? null, numItems: batchSize });
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
items: results.page,
|
|
153
|
+
cursor: results.continueCursor,
|
|
154
|
+
done: results.isDone,
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
export const processBatch = internalAction({
|
|
160
|
+
args: { items: v.array(userValidator) },
|
|
161
|
+
handler: async (ctx, { items }) => {
|
|
162
|
+
for (const user of items) {
|
|
163
|
+
await migrateUser(user);
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
export const onComplete = internalMutation({
|
|
169
|
+
args: {
|
|
170
|
+
jobId: v.string(),
|
|
171
|
+
processedCount: v.number(),
|
|
172
|
+
},
|
|
173
|
+
handler: async (ctx, { jobId, processedCount }) => {
|
|
174
|
+
console.log(`Migration ${jobId} completed: ${processedCount} users`);
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### Job Control
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
export const pause = mutation({
|
|
183
|
+
args: { jobId: v.string() },
|
|
184
|
+
handler: async (ctx, { jobId }) => {
|
|
185
|
+
return await batchProcessor.pauseIterator(ctx, jobId);
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
export const resume = mutation({
|
|
190
|
+
args: { jobId: v.string() },
|
|
191
|
+
handler: async (ctx, { jobId }) => {
|
|
192
|
+
return await batchProcessor.resumeIterator(ctx, jobId);
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
export const cancel = mutation({
|
|
197
|
+
args: { jobId: v.string() },
|
|
198
|
+
handler: async (ctx, { jobId }) => {
|
|
199
|
+
return await batchProcessor.cancelIterator(ctx, jobId);
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
export const getStatus = query({
|
|
204
|
+
args: { jobId: v.string() },
|
|
205
|
+
handler: async (ctx, { jobId }) => {
|
|
206
|
+
return await batchProcessor.getIteratorStatus(ctx, jobId);
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
export const listJobs = query({
|
|
211
|
+
args: { status: v.optional(v.string()) },
|
|
212
|
+
handler: async (ctx, { status }) => {
|
|
213
|
+
return await batchProcessor.listIteratorJobs(ctx, { status });
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## API Reference
|
|
219
|
+
|
|
220
|
+
### BatchProcessor Class
|
|
221
|
+
|
|
222
|
+
#### Batch Accumulator Methods
|
|
223
|
+
|
|
224
|
+
| Method | Description |
|
|
225
|
+
|--------|-------------|
|
|
226
|
+
| `addItems(ctx, batchId, items)` | Add items to a batch |
|
|
227
|
+
| `flush(ctx, batchId)` | Force flush a batch |
|
|
228
|
+
| `getBatchStatus(ctx, batchId)` | Get batch status |
|
|
229
|
+
| `getFlushHistory(ctx, batchId, limit?)` | Get flush history |
|
|
230
|
+
| `deleteBatch(ctx, batchId)` | Delete a completed batch |
|
|
231
|
+
|
|
232
|
+
#### Table Iterator Methods
|
|
233
|
+
|
|
234
|
+
| Method | Description |
|
|
235
|
+
|--------|-------------|
|
|
236
|
+
| `startIterator(ctx, jobId, config)` | Start a new iterator job |
|
|
237
|
+
| `pauseIterator(ctx, jobId)` | Pause a running job |
|
|
238
|
+
| `resumeIterator(ctx, jobId)` | Resume a paused job |
|
|
239
|
+
| `cancelIterator(ctx, jobId)` | Cancel a job |
|
|
240
|
+
| `getIteratorStatus(ctx, jobId)` | Get job status |
|
|
241
|
+
| `listIteratorJobs(ctx, options?)` | List jobs |
|
|
242
|
+
| `deleteIteratorJob(ctx, jobId)` | Delete a completed job |
|
|
243
|
+
|
|
244
|
+
### Types
|
|
245
|
+
|
|
246
|
+
#### BatchConfig
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
interface BatchConfig<T = unknown> {
|
|
250
|
+
maxBatchSize: number;
|
|
251
|
+
flushIntervalMs: number;
|
|
252
|
+
processBatch: FunctionReference<"action", "internal", { items: T[] }>;
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**`processBatch` Requirements:**
|
|
257
|
+
|
|
258
|
+
The `processBatch` **must be a Convex action** (not a mutation or plain JavaScript function). This is because:
|
|
259
|
+
- The batch processor is called via `ctx.runAction()` internally
|
|
260
|
+
- Actions can perform async operations like HTTP requests, which is the typical use case for batch processing (e.g., sending events to an external analytics service)
|
|
261
|
+
|
|
262
|
+
Pass the function reference directly:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
const batchProcessor: BatchProcessor<MyEvent> = new BatchProcessor(components.batchProcessor, {
|
|
266
|
+
maxBatchSize: 100,
|
|
267
|
+
flushIntervalMs: 30000,
|
|
268
|
+
processBatch: internal.myModule.processBatch,
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
If you only need to write to the database (no external calls), you can still use an action that calls a mutation internally:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
export const processBatch = internalAction({
|
|
276
|
+
args: { items: v.array(myItemValidator) },
|
|
277
|
+
handler: async (ctx, { items }) => {
|
|
278
|
+
await ctx.runMutation(internal.myModule.writeBatchToDb, { items });
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### BatchResult
|
|
284
|
+
|
|
285
|
+
Returned by `addItems()`:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
interface BatchResult {
|
|
289
|
+
batchId: string; // Same ID you passed in
|
|
290
|
+
itemCount: number; // Items added in THIS call (use getBatchStatus for total)
|
|
291
|
+
flushed: boolean; // Whether batch was flushed
|
|
292
|
+
status: BatchStatus; // "accumulating" | "flushing" | "completed"
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### BatchStatusResult
|
|
297
|
+
|
|
298
|
+
Returned by `getBatchStatus()`:
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
interface BatchStatusResult {
|
|
302
|
+
batchId: string; // Same ID you passed in
|
|
303
|
+
batches: Array<{
|
|
304
|
+
status: "accumulating" | "flushing";
|
|
305
|
+
itemCount: number;
|
|
306
|
+
createdAt: number;
|
|
307
|
+
lastUpdatedAt: number;
|
|
308
|
+
}>;
|
|
309
|
+
config: {
|
|
310
|
+
maxBatchSize: number;
|
|
311
|
+
flushIntervalMs: number;
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The `batches` array contains all active batches. Typically there's one, but during flush there may be both a flushing batch and a new accumulating batch.
|
|
317
|
+
|
|
318
|
+
#### IteratorConfig
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
interface IteratorConfig<T = unknown> {
|
|
322
|
+
batchSize: number;
|
|
323
|
+
delayBetweenBatchesMs?: number;
|
|
324
|
+
getNextBatch: FunctionReference<"query", "internal", { cursor: string | undefined; batchSize: number }>;
|
|
325
|
+
processBatch: FunctionReference<"action", "internal", { items: T[] }>;
|
|
326
|
+
onComplete?: FunctionReference<"mutation", "internal", { jobId: string; processedCount: number }>;
|
|
327
|
+
maxRetries?: number;
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### Callback Types
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
interface GetNextBatchResult<T = unknown> {
|
|
335
|
+
items: T[];
|
|
336
|
+
cursor: string | undefined;
|
|
337
|
+
done: boolean;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
interface ProcessBatchArgs<T = unknown> {
|
|
341
|
+
items: T[];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
interface OnCompleteArgs {
|
|
345
|
+
jobId: string;
|
|
346
|
+
processedCount: number;
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## TypeScript Notes
|
|
351
|
+
|
|
352
|
+
### Explicit Type Annotation Required
|
|
353
|
+
|
|
354
|
+
When creating a `BatchProcessor` with config in a file that also exports Convex functions (mutations, queries, actions), you must add an explicit type annotation:
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
// ✅ Correct - explicit type annotation
|
|
358
|
+
const batchProcessor: BatchProcessor<MyEvent> = new BatchProcessor(components.batchProcessor, {
|
|
359
|
+
processBatch: internal.myModule.processBatch,
|
|
360
|
+
// ...
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// ❌ Will cause error TS7022
|
|
364
|
+
const batchProcessor = new BatchProcessor<MyEvent>(components.batchProcessor, {
|
|
365
|
+
processBatch: internal.myModule.processBatch,
|
|
366
|
+
// ...
|
|
367
|
+
});
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
This is due to circular type inference: TypeScript can't infer the type because the `internal` API types are generated from your file's exports, creating a circular dependency. The explicit annotation breaks this cycle.
|
|
371
|
+
|
|
372
|
+
## Error Handling
|
|
373
|
+
|
|
374
|
+
### Batch Accumulator
|
|
375
|
+
- Failed flushes are recorded in `flushHistory`
|
|
376
|
+
- Items are preserved for retry (batch reverts to "accumulating" state)
|
|
377
|
+
|
|
378
|
+
### Table Iterator
|
|
379
|
+
- Automatic retry with exponential backoff (1s, 2s, 4s... up to 30s)
|
|
380
|
+
- Job marked as "failed" after `maxRetries` attempts
|
|
381
|
+
- Error messages preserved in job status
|
|
382
|
+
|
|
383
|
+
## Development
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
pnpm install
|
|
387
|
+
pnpm run build
|
|
388
|
+
pnpm test
|
|
389
|
+
pnpm run lint
|
|
390
|
+
pnpm run format
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## License
|
|
394
|
+
|
|
395
|
+
MIT
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { type FunctionReference, type GenericMutationCtx, type GenericQueryCtx } from "convex/server";
|
|
2
|
+
export type BatchStatus = "accumulating" | "flushing" | "completed";
|
|
3
|
+
export type JobStatus = "pending" | "running" | "paused" | "completed" | "failed";
|
|
4
|
+
export interface BatchConfig<T = unknown> {
|
|
5
|
+
maxBatchSize: number;
|
|
6
|
+
flushIntervalMs: number;
|
|
7
|
+
processBatch: FunctionReference<"action", "internal", {
|
|
8
|
+
items: T[];
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
export interface IteratorConfig<T = unknown> {
|
|
12
|
+
batchSize: number;
|
|
13
|
+
delayBetweenBatchesMs?: number;
|
|
14
|
+
getNextBatch: FunctionReference<"query", "internal", {
|
|
15
|
+
cursor: string | undefined;
|
|
16
|
+
batchSize: number;
|
|
17
|
+
}>;
|
|
18
|
+
processBatch: FunctionReference<"action", "internal", {
|
|
19
|
+
items: T[];
|
|
20
|
+
}>;
|
|
21
|
+
onComplete?: FunctionReference<"mutation", "internal", {
|
|
22
|
+
jobId: string;
|
|
23
|
+
processedCount: number;
|
|
24
|
+
}>;
|
|
25
|
+
maxRetries?: number;
|
|
26
|
+
}
|
|
27
|
+
interface InternalBatchConfig {
|
|
28
|
+
maxBatchSize: number;
|
|
29
|
+
flushIntervalMs: number;
|
|
30
|
+
processBatchHandle: string;
|
|
31
|
+
}
|
|
32
|
+
interface InternalIteratorConfig {
|
|
33
|
+
batchSize: number;
|
|
34
|
+
delayBetweenBatchesMs?: number;
|
|
35
|
+
getNextBatchHandle: string;
|
|
36
|
+
processBatchHandle: string;
|
|
37
|
+
onCompleteHandle?: string;
|
|
38
|
+
maxRetries?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface BatchResult {
|
|
41
|
+
batchId: string;
|
|
42
|
+
itemCount: number;
|
|
43
|
+
flushed: boolean;
|
|
44
|
+
status: BatchStatus;
|
|
45
|
+
}
|
|
46
|
+
export interface FlushResult {
|
|
47
|
+
batchId: string;
|
|
48
|
+
itemCount: number;
|
|
49
|
+
flushed: boolean;
|
|
50
|
+
status?: BatchStatus;
|
|
51
|
+
reason?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface BatchStatusResult {
|
|
54
|
+
batchId: string;
|
|
55
|
+
batches: Array<{
|
|
56
|
+
status: "accumulating" | "flushing";
|
|
57
|
+
itemCount: number;
|
|
58
|
+
createdAt: number;
|
|
59
|
+
lastUpdatedAt: number;
|
|
60
|
+
}>;
|
|
61
|
+
config: {
|
|
62
|
+
maxBatchSize: number;
|
|
63
|
+
flushIntervalMs: number;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export interface BatchListItem {
|
|
67
|
+
batchId: string;
|
|
68
|
+
baseBatchId: string;
|
|
69
|
+
sequence: number;
|
|
70
|
+
itemCount: number;
|
|
71
|
+
status: BatchStatus;
|
|
72
|
+
createdAt: number;
|
|
73
|
+
lastUpdatedAt: number;
|
|
74
|
+
}
|
|
75
|
+
export interface JobResult {
|
|
76
|
+
jobId: string;
|
|
77
|
+
status: JobStatus;
|
|
78
|
+
}
|
|
79
|
+
export interface JobStatusResult {
|
|
80
|
+
jobId: string;
|
|
81
|
+
status: JobStatus;
|
|
82
|
+
processedCount: number;
|
|
83
|
+
cursor?: string;
|
|
84
|
+
retryCount: number;
|
|
85
|
+
errorMessage?: string;
|
|
86
|
+
createdAt: number;
|
|
87
|
+
lastRunAt?: number;
|
|
88
|
+
config: {
|
|
89
|
+
batchSize: number;
|
|
90
|
+
delayBetweenBatchesMs: number;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export interface JobListItem {
|
|
94
|
+
jobId: string;
|
|
95
|
+
status: JobStatus;
|
|
96
|
+
processedCount: number;
|
|
97
|
+
createdAt: number;
|
|
98
|
+
lastRunAt?: number;
|
|
99
|
+
errorMessage?: string;
|
|
100
|
+
}
|
|
101
|
+
export interface FlushHistoryItem {
|
|
102
|
+
batchId: string;
|
|
103
|
+
itemCount: number;
|
|
104
|
+
flushedAt: number;
|
|
105
|
+
durationMs: number;
|
|
106
|
+
success: boolean;
|
|
107
|
+
errorMessage?: string;
|
|
108
|
+
}
|
|
109
|
+
export interface BatchProcessorAPI {
|
|
110
|
+
lib: {
|
|
111
|
+
addItems: FunctionReference<"mutation", "internal", {
|
|
112
|
+
batchId: string;
|
|
113
|
+
items: unknown[];
|
|
114
|
+
config: InternalBatchConfig;
|
|
115
|
+
}, BatchResult>;
|
|
116
|
+
flushBatch: FunctionReference<"mutation", "internal", {
|
|
117
|
+
batchId: string;
|
|
118
|
+
}, FlushResult>;
|
|
119
|
+
getBatchStatus: FunctionReference<"query", "internal", {
|
|
120
|
+
batchId: string;
|
|
121
|
+
}, BatchStatusResult | null>;
|
|
122
|
+
getFlushHistory: FunctionReference<"query", "internal", {
|
|
123
|
+
batchId: string;
|
|
124
|
+
limit?: number;
|
|
125
|
+
}, FlushHistoryItem[]>;
|
|
126
|
+
getAllBatchesForBaseId: FunctionReference<"query", "internal", {
|
|
127
|
+
baseBatchId: string;
|
|
128
|
+
}, BatchListItem[]>;
|
|
129
|
+
deleteBatch: FunctionReference<"mutation", "internal", {
|
|
130
|
+
batchId: string;
|
|
131
|
+
}, {
|
|
132
|
+
deleted: boolean;
|
|
133
|
+
reason?: string;
|
|
134
|
+
}>;
|
|
135
|
+
startIteratorJob: FunctionReference<"mutation", "internal", {
|
|
136
|
+
jobId: string;
|
|
137
|
+
config: InternalIteratorConfig;
|
|
138
|
+
}, JobResult>;
|
|
139
|
+
pauseIteratorJob: FunctionReference<"mutation", "internal", {
|
|
140
|
+
jobId: string;
|
|
141
|
+
}, JobResult>;
|
|
142
|
+
resumeIteratorJob: FunctionReference<"mutation", "internal", {
|
|
143
|
+
jobId: string;
|
|
144
|
+
}, JobResult>;
|
|
145
|
+
cancelIteratorJob: FunctionReference<"mutation", "internal", {
|
|
146
|
+
jobId: string;
|
|
147
|
+
}, JobResult & {
|
|
148
|
+
reason?: string;
|
|
149
|
+
}>;
|
|
150
|
+
getIteratorJobStatus: FunctionReference<"query", "internal", {
|
|
151
|
+
jobId: string;
|
|
152
|
+
}, JobStatusResult | null>;
|
|
153
|
+
listIteratorJobs: FunctionReference<"query", "internal", {
|
|
154
|
+
status?: JobStatus;
|
|
155
|
+
limit?: number;
|
|
156
|
+
}, JobListItem[]>;
|
|
157
|
+
deleteIteratorJob: FunctionReference<"mutation", "internal", {
|
|
158
|
+
jobId: string;
|
|
159
|
+
}, {
|
|
160
|
+
deleted: boolean;
|
|
161
|
+
reason?: string;
|
|
162
|
+
}>;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
export declare class BatchProcessor<T = unknown> {
|
|
166
|
+
private component;
|
|
167
|
+
private config?;
|
|
168
|
+
private processBatchHandle;
|
|
169
|
+
constructor(component: BatchProcessorAPI, config?: BatchConfig<T>);
|
|
170
|
+
addItems(ctx: GenericMutationCtx<any>, batchId: string, items: T[]): Promise<BatchResult>;
|
|
171
|
+
flush(ctx: GenericMutationCtx<any>, batchId: string): Promise<FlushResult>;
|
|
172
|
+
getBatchStatus(ctx: GenericQueryCtx<any>, batchId: string): Promise<BatchStatusResult | null>;
|
|
173
|
+
getFlushHistory(ctx: GenericQueryCtx<any>, batchId: string, limit?: number): Promise<FlushHistoryItem[]>;
|
|
174
|
+
getAllBatchesForBaseId(ctx: GenericQueryCtx<any>, baseBatchId: string): Promise<BatchListItem[]>;
|
|
175
|
+
deleteBatch(ctx: GenericMutationCtx<any>, batchId: string): Promise<{
|
|
176
|
+
deleted: boolean;
|
|
177
|
+
reason?: string;
|
|
178
|
+
}>;
|
|
179
|
+
startIterator<T>(ctx: GenericMutationCtx<any>, jobId: string, config: IteratorConfig<T>): Promise<JobResult>;
|
|
180
|
+
pauseIterator(ctx: GenericMutationCtx<any>, jobId: string): Promise<JobResult>;
|
|
181
|
+
resumeIterator(ctx: GenericMutationCtx<any>, jobId: string): Promise<JobResult>;
|
|
182
|
+
cancelIterator(ctx: GenericMutationCtx<any>, jobId: string): Promise<JobResult & {
|
|
183
|
+
reason?: string;
|
|
184
|
+
}>;
|
|
185
|
+
getIteratorStatus(ctx: GenericQueryCtx<any>, jobId: string): Promise<JobStatusResult | null>;
|
|
186
|
+
listIteratorJobs(ctx: GenericQueryCtx<any>, options?: {
|
|
187
|
+
status?: JobStatus;
|
|
188
|
+
limit?: number;
|
|
189
|
+
}): Promise<JobListItem[]>;
|
|
190
|
+
deleteIteratorJob(ctx: GenericMutationCtx<any>, jobId: string): Promise<{
|
|
191
|
+
deleted: boolean;
|
|
192
|
+
reason?: string;
|
|
193
|
+
}>;
|
|
194
|
+
}
|
|
195
|
+
export interface GetNextBatchResult<T = unknown> {
|
|
196
|
+
items: T[];
|
|
197
|
+
cursor: string | undefined;
|
|
198
|
+
done: boolean;
|
|
199
|
+
}
|
|
200
|
+
export interface GetNextBatchArgs {
|
|
201
|
+
cursor: string | undefined;
|
|
202
|
+
batchSize: number;
|
|
203
|
+
}
|
|
204
|
+
export interface ProcessBatchArgs<T = unknown> {
|
|
205
|
+
items: T[];
|
|
206
|
+
}
|
|
207
|
+
export interface OnCompleteArgs {
|
|
208
|
+
jobId: string;
|
|
209
|
+
processedCount: number;
|
|
210
|
+
}
|
|
211
|
+
export {};
|
|
212
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
|