create-bcp-app 0.2.10 → 0.2.11
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 +67 -67
- package/package.json +1 -1
- package/template/README.md +78 -0
package/README.md
CHANGED
|
@@ -92,10 +92,10 @@ Example:
|
|
|
92
92
|
"schemaVersion": 1,
|
|
93
93
|
"framework": "bcp",
|
|
94
94
|
"projectName": "my-app",
|
|
95
|
-
"frameworkPackage": "npm:@chidchanun/bcp@0.2.
|
|
95
|
+
"frameworkPackage": "npm:@chidchanun/bcp@0.2.11",
|
|
96
96
|
"createdWith": {
|
|
97
97
|
"package": "create-bcp-app",
|
|
98
|
-
"version": "0.2.
|
|
98
|
+
"version": "0.2.11"
|
|
99
99
|
},
|
|
100
100
|
"packageManager": "npm",
|
|
101
101
|
"presets": {
|
|
@@ -263,87 +263,87 @@ const worker =
|
|
|
263
263
|
});
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
-
|
|
266
|
+
BCP intentionally does not install a Redis client library. Applications own the Redis connection and can pass a minimal `RedisCommandClient` to `createRedisJobQueueAdapter()` and `createRedisJobScheduleStore()`.
|
|
267
267
|
|
|
268
|
-
|
|
269
|
-
const deadLetters =
|
|
270
|
-
await jobs.deadLetters();
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
Requeue:
|
|
274
|
-
|
|
275
|
-
```ts
|
|
276
|
-
await jobs.requeueDeadLetter(
|
|
277
|
-
deadLetters[0].id,
|
|
278
|
-
{
|
|
279
|
-
resetAttempts: true,
|
|
280
|
-
}
|
|
281
|
-
);
|
|
282
|
-
```
|
|
268
|
+
`bcp/jobs` is server-only and must not be imported into page/client bundles.
|
|
283
269
|
|
|
284
|
-
|
|
270
|
+
## Workflow orchestration — 0.2.11+
|
|
285
271
|
|
|
286
|
-
|
|
272
|
+
Generated applications can define persistent backend workflows with the new server-only `bcp/workflow` entrypoint:
|
|
287
273
|
|
|
288
274
|
```ts
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
275
|
+
import {
|
|
276
|
+
createWorkflow,
|
|
277
|
+
} from "bcp/workflow";
|
|
278
|
+
|
|
279
|
+
export const onboarding =
|
|
280
|
+
createWorkflow<{
|
|
281
|
+
userId: number;
|
|
282
|
+
}>(
|
|
283
|
+
"user.onboarding",
|
|
284
|
+
workflow => {
|
|
285
|
+
workflow.step(
|
|
286
|
+
"profile",
|
|
287
|
+
createProfile
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
workflow.parallel(
|
|
291
|
+
"initialize",
|
|
292
|
+
parallel => {
|
|
293
|
+
parallel.step(
|
|
294
|
+
"preferences",
|
|
295
|
+
createPreferences
|
|
296
|
+
);
|
|
297
|
+
parallel.step(
|
|
298
|
+
"workspace",
|
|
299
|
+
createWorkspace
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
workflow.delay(
|
|
305
|
+
"cooldown",
|
|
306
|
+
1_000
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
);
|
|
294
310
|
```
|
|
295
311
|
|
|
296
|
-
|
|
312
|
+
Step-level retry and compensation are supported:
|
|
297
313
|
|
|
298
314
|
```ts
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
export const jobs =
|
|
311
|
-
createJobQueue({
|
|
312
|
-
adapter,
|
|
313
|
-
});
|
|
315
|
+
workflow.step(
|
|
316
|
+
"reserve-stock",
|
|
317
|
+
reserveStock,
|
|
318
|
+
{
|
|
319
|
+
maxAttempts: 3,
|
|
320
|
+
retryDelayMs: 1_000,
|
|
321
|
+
compensate:
|
|
322
|
+
releaseStock,
|
|
323
|
+
}
|
|
324
|
+
);
|
|
314
325
|
```
|
|
315
326
|
|
|
316
|
-
|
|
327
|
+
For durable queue-backed execution, pass an existing `BackgroundJobQueue` and a durable shared `WorkflowStore`:
|
|
317
328
|
|
|
318
329
|
```ts
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
export const scheduler =
|
|
331
|
-
createJobScheduler({
|
|
332
|
-
queue: jobs,
|
|
333
|
-
store,
|
|
334
|
-
ownerId: "scheduler-a",
|
|
335
|
-
});
|
|
330
|
+
const fulfillment =
|
|
331
|
+
createWorkflow(
|
|
332
|
+
"order.fulfillment",
|
|
333
|
+
defineWorkflow,
|
|
334
|
+
{
|
|
335
|
+
queue: jobs,
|
|
336
|
+
store:
|
|
337
|
+
workflowStore,
|
|
338
|
+
}
|
|
339
|
+
);
|
|
336
340
|
```
|
|
337
341
|
|
|
338
|
-
|
|
342
|
+
The built-in `createMemoryWorkflowStore()` is intended for development/tests. Multi-instance production stores should make `claim()` atomic so only one executor owns a workflow run lease at a time.
|
|
339
343
|
|
|
340
|
-
|
|
341
|
-
REDIS_URL=redis://localhost:6379
|
|
342
|
-
```
|
|
344
|
+
External side effects should remain idempotent because durable queue execution is at-least-once.
|
|
343
345
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
`bcp/jobs` is server-only and must not be imported into page/client bundles.
|
|
346
|
+
`bcp/workflow` is server-only and cannot be imported into page/client bundles.
|
|
347
347
|
|
|
348
348
|
## Application Packaging — 0.2.4+
|
|
349
349
|
|
|
@@ -390,5 +390,5 @@ bcp generate migration create_users
|
|
|
390
390
|
The `--bcp` option is mainly for prerelease/local package verification:
|
|
391
391
|
|
|
392
392
|
```bash
|
|
393
|
-
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.
|
|
393
|
+
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.11.tgz
|
|
394
394
|
```
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -216,6 +216,84 @@ The processing model is at-least-once, so side-effecting job handlers should be
|
|
|
216
216
|
|
|
217
217
|
`bcp/jobs` is server-only and cannot be imported into page/client bundles.
|
|
218
218
|
|
|
219
|
+
## Workflow orchestration — BCP 0.2.11+
|
|
220
|
+
|
|
221
|
+
Define persistent server-side workflows through `bcp/workflow`:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import {
|
|
225
|
+
createWorkflow,
|
|
226
|
+
} from "bcp/workflow";
|
|
227
|
+
|
|
228
|
+
export const onboarding =
|
|
229
|
+
createWorkflow<{
|
|
230
|
+
userId: number;
|
|
231
|
+
}>(
|
|
232
|
+
"user.onboarding",
|
|
233
|
+
workflow => {
|
|
234
|
+
workflow.step(
|
|
235
|
+
"profile",
|
|
236
|
+
createProfile
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
workflow.parallel(
|
|
240
|
+
"initialize",
|
|
241
|
+
parallel => {
|
|
242
|
+
parallel.step(
|
|
243
|
+
"preferences",
|
|
244
|
+
createPreferences
|
|
245
|
+
);
|
|
246
|
+
parallel.step(
|
|
247
|
+
"workspace",
|
|
248
|
+
createWorkspace
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
workflow.delay(
|
|
254
|
+
"cooldown",
|
|
255
|
+
1_000
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Step retry and compensation:
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
workflow.step(
|
|
265
|
+
"reserve-stock",
|
|
266
|
+
reserveStock,
|
|
267
|
+
{
|
|
268
|
+
maxAttempts: 3,
|
|
269
|
+
retryDelayMs: 1_000,
|
|
270
|
+
compensate:
|
|
271
|
+
releaseStock,
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
For queue-backed execution:
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
const fulfillment =
|
|
280
|
+
createWorkflow(
|
|
281
|
+
"order.fulfillment",
|
|
282
|
+
defineWorkflow,
|
|
283
|
+
{
|
|
284
|
+
queue: jobs,
|
|
285
|
+
store:
|
|
286
|
+
workflowStore,
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The default `createMemoryWorkflowStore()` is for local development/tests. Multi-instance production deployments should implement a shared durable `WorkflowStore` with atomic `claim()` behavior.
|
|
292
|
+
|
|
293
|
+
Workflow handlers that perform external side effects should be idempotent because durable job execution is at-least-once.
|
|
294
|
+
|
|
295
|
+
`bcp/workflow` is server-only and cannot be imported into page/client bundles.
|
|
296
|
+
|
|
219
297
|
## Generate framework files
|
|
220
298
|
|
|
221
299
|
```bash
|