@chidchanun/bcp 0.2.10 → 0.2.12
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 +231 -286
- package/docs/README.md +60 -61
- package/docs/api-manifest.json +29 -2
- package/docs/api-reference.md +105 -85
- package/docs/docs-web-manifest.json +9 -5
- package/docs/platform-manifest.json +27 -4
- package/docs/releases/0.2.11.md +180 -0
- package/docs/releases/0.2.12.md +147 -0
- package/docs/transactional-outbox-events.md +465 -0
- package/docs/workflow-orchestration.md +374 -0
- package/package.json +11 -1
- package/packages/bundler/src/client-boundary.ts +2 -0
- package/packages/client/src/events.mjs +889 -0
- package/packages/client/src/events.ts +31 -0
- package/packages/client/src/workflow.mjs +601 -0
- package/packages/client/src/workflow.ts +23 -0
- package/packages/server/src/events.ts +1416 -0
- package/packages/server/src/workflow.ts +887 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# BCP Framework 0.2.11 — Workflow Orchestration
|
|
2
|
+
|
|
3
|
+
> Release state: unreleased development target until RC validation, tagging and npm publication complete.
|
|
4
|
+
|
|
5
|
+
`0.2.11` adds server-side workflow orchestration on top of the durable jobs foundation introduced in `0.2.8`–`0.2.10`.
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- new `bcp/workflow` server-only public entrypoint,
|
|
10
|
+
- sequential workflow steps,
|
|
11
|
+
- parallel step groups,
|
|
12
|
+
- per-step retry policies,
|
|
13
|
+
- persisted workflow delays,
|
|
14
|
+
- manual resume/retry/cancel controls,
|
|
15
|
+
- saga-style compensation in reverse completion order,
|
|
16
|
+
- `WorkflowStore` persistence contract,
|
|
17
|
+
- workflow run leases via atomic `claim()` / `release()`,
|
|
18
|
+
- optional `bcp/jobs` queue-backed execution,
|
|
19
|
+
- delayed workflow continuation through the job queue,
|
|
20
|
+
- compiled `workflow.mjs` runtime in the npm package,
|
|
21
|
+
- browser/client bundle boundary enforcement,
|
|
22
|
+
- unit and prepared-package smoke coverage.
|
|
23
|
+
|
|
24
|
+
## Basic API
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import {
|
|
28
|
+
createWorkflow,
|
|
29
|
+
} from "bcp/workflow";
|
|
30
|
+
|
|
31
|
+
const onboarding =
|
|
32
|
+
createWorkflow<{
|
|
33
|
+
userId: number;
|
|
34
|
+
}>(
|
|
35
|
+
"user.onboarding",
|
|
36
|
+
workflow => {
|
|
37
|
+
workflow.step(
|
|
38
|
+
"profile",
|
|
39
|
+
createProfile
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
workflow.parallel(
|
|
43
|
+
"initialize",
|
|
44
|
+
parallel => {
|
|
45
|
+
parallel.step(
|
|
46
|
+
"preferences",
|
|
47
|
+
createPreferences
|
|
48
|
+
);
|
|
49
|
+
parallel.step(
|
|
50
|
+
"workspace",
|
|
51
|
+
createWorkspace
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
workflow.delay(
|
|
57
|
+
"cooldown",
|
|
58
|
+
1_000
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Queue-backed workflows
|
|
65
|
+
|
|
66
|
+
Applications may provide an existing `BackgroundJobQueue`:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
const workflow =
|
|
70
|
+
createWorkflow(
|
|
71
|
+
"order.fulfillment",
|
|
72
|
+
defineWorkflow,
|
|
73
|
+
{
|
|
74
|
+
queue: jobs,
|
|
75
|
+
store:
|
|
76
|
+
workflowStore,
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`start()`, `retry()` and `resume()` then enqueue workflow execution rather than executing the run inline. Delay steps enqueue delayed continuation jobs.
|
|
82
|
+
|
|
83
|
+
The queue retains responsibility for delivery, worker concurrency, visibility timeout, heartbeat and stale-job recovery.
|
|
84
|
+
|
|
85
|
+
## Persistence
|
|
86
|
+
|
|
87
|
+
`createMemoryWorkflowStore()` is included for development/tests.
|
|
88
|
+
|
|
89
|
+
Production multi-instance deployments should implement `WorkflowStore` with shared durable storage. `claim()` must atomically lease a workflow run so multiple workers cannot execute the same run concurrently.
|
|
90
|
+
|
|
91
|
+
## Retry behavior
|
|
92
|
+
|
|
93
|
+
A step can define:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
{
|
|
97
|
+
maxAttempts: 3,
|
|
98
|
+
retryDelayMs:
|
|
99
|
+
attempt =>
|
|
100
|
+
attempt * 1_000,
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
A run that remains failed after its step retry policy is exhausted can later be retried with:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
await workflow.retry(
|
|
108
|
+
runId
|
|
109
|
+
);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Already-successful preceding steps remain complete.
|
|
113
|
+
|
|
114
|
+
## Compensation
|
|
115
|
+
|
|
116
|
+
Steps can define compensation handlers:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
workflow.step(
|
|
120
|
+
"reserve-stock",
|
|
121
|
+
reserveStock,
|
|
122
|
+
{
|
|
123
|
+
compensate:
|
|
124
|
+
releaseStock,
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Then:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
await workflow.compensate(
|
|
133
|
+
runId
|
|
134
|
+
);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Successful compensatable steps execute in reverse completion order.
|
|
138
|
+
|
|
139
|
+
## Delays
|
|
140
|
+
|
|
141
|
+
Delay steps persist `waiting` state and `waitUntil` rather than holding a long-running process timer.
|
|
142
|
+
|
|
143
|
+
Without a queue, application code calls `resume()` after the due time. With a queue, BCP schedules a delayed workflow continuation job.
|
|
144
|
+
|
|
145
|
+
## Compatibility
|
|
146
|
+
|
|
147
|
+
`0.2.11` is additive relative to `0.2.10`.
|
|
148
|
+
|
|
149
|
+
Existing `bcp/jobs`, scheduler, Redis durable adapters and all prior public entrypoints remain supported.
|
|
150
|
+
|
|
151
|
+
No intentional breaking changes are introduced from the `0.2.10` baseline.
|
|
152
|
+
|
|
153
|
+
## Validation
|
|
154
|
+
|
|
155
|
+
Before release:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npm run typecheck
|
|
159
|
+
npm run test:unit
|
|
160
|
+
npm run test:integration
|
|
161
|
+
npm run test:e2e
|
|
162
|
+
npm run test:package
|
|
163
|
+
npm run rc:check
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Workflow validation covers:
|
|
167
|
+
|
|
168
|
+
- sequential step execution,
|
|
169
|
+
- transient step retry,
|
|
170
|
+
- parallel groups,
|
|
171
|
+
- persisted delay/resume semantics,
|
|
172
|
+
- manual failed-run retry,
|
|
173
|
+
- reverse compensation order,
|
|
174
|
+
- queue-backed execution,
|
|
175
|
+
- workflow store lease behavior,
|
|
176
|
+
- browser bundle rejection,
|
|
177
|
+
- compiled `workflow.mjs` package execution,
|
|
178
|
+
- API/platform/docs manifest parity.
|
|
179
|
+
|
|
180
|
+
The final release tag must point to the exact commit that passed the complete RC sequence.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# BCP Framework 0.2.12 — Transactional Outbox & Events
|
|
2
|
+
|
|
3
|
+
Release state: unreleased development target.
|
|
4
|
+
|
|
5
|
+
`0.2.12` adds a server-only transactional outbox and event-delivery platform that bridges BCP Database transactions with durable jobs or application-owned publishers without performing external side effects inside the business transaction.
|
|
6
|
+
|
|
7
|
+
## New public entrypoint
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {
|
|
11
|
+
createEventBus,
|
|
12
|
+
createMemoryOutboxStore,
|
|
13
|
+
createOutboxDispatcher,
|
|
14
|
+
createOutboxMigrationSql,
|
|
15
|
+
createSqlOutboxStore,
|
|
16
|
+
createTransactionalOutbox,
|
|
17
|
+
} from "bcp/events";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`bcp/events` is server-only and receives the same browser/client boundary protection as `bcp/database`, `bcp/jobs` and `bcp/workflow`.
|
|
21
|
+
|
|
22
|
+
## Transaction-bound outbox writes
|
|
23
|
+
|
|
24
|
+
Application code can insert business rows and outbox rows through the same `TransactionDatabase`:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
await db.transaction(async tx => {
|
|
28
|
+
await tx.execute(
|
|
29
|
+
"INSERT INTO orders ..."
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
await outbox.publish(
|
|
33
|
+
tx,
|
|
34
|
+
"order.created",
|
|
35
|
+
{
|
|
36
|
+
orderId: 42,
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`createSqlOutboxStore()` writes through the caller transaction rather than the root database connection.
|
|
43
|
+
|
|
44
|
+
## SQL providers
|
|
45
|
+
|
|
46
|
+
Provider-specific migration SQL is available for:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
mysql
|
|
50
|
+
postgresql
|
|
51
|
+
sqlite
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The SQL store persists:
|
|
55
|
+
|
|
56
|
+
- event ID/type/payload,
|
|
57
|
+
- metadata,
|
|
58
|
+
- correlation/causation/aggregate IDs,
|
|
59
|
+
- state,
|
|
60
|
+
- attempts/max attempts,
|
|
61
|
+
- created/available/processing/published/failed timestamps,
|
|
62
|
+
- delivery errors,
|
|
63
|
+
- lease owner/expiry.
|
|
64
|
+
|
|
65
|
+
## Dispatcher
|
|
66
|
+
|
|
67
|
+
`createOutboxDispatcher()` adds:
|
|
68
|
+
|
|
69
|
+
- batched claiming,
|
|
70
|
+
- dispatcher leases,
|
|
71
|
+
- stale-lease recovery,
|
|
72
|
+
- retry/backoff,
|
|
73
|
+
- terminal failed state,
|
|
74
|
+
- durable job-queue handoff,
|
|
75
|
+
- custom publisher delivery,
|
|
76
|
+
- in-process EventBus delivery,
|
|
77
|
+
- polling runner lifecycle,
|
|
78
|
+
- cleanup/statistics through the store.
|
|
79
|
+
|
|
80
|
+
## Durable job handoff
|
|
81
|
+
|
|
82
|
+
With `queue: jobs`, event type:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
order.created
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
is handed off as:
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
event.order.created
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The queued payload contains the event envelope and uses stable job ID:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
outbox:<event-id>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
A successful enqueue marks the outbox event `published`. Downstream job completion remains the responsibility of the job runtime.
|
|
101
|
+
|
|
102
|
+
## Event bus
|
|
103
|
+
|
|
104
|
+
`createEventBus()` provides local server-side handler registration and sequential event delivery for tests, local composition and single-process handlers.
|
|
105
|
+
|
|
106
|
+
It is not a distributed durable broker.
|
|
107
|
+
|
|
108
|
+
## States
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
pending
|
|
112
|
+
processing
|
|
113
|
+
published
|
|
114
|
+
failed
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Expired `processing` leases can return to `pending` for another dispatcher attempt.
|
|
118
|
+
|
|
119
|
+
## Delivery semantics
|
|
120
|
+
|
|
121
|
+
The platform closes the database-commit / external-publish gap but intentionally uses at-least-once delivery semantics.
|
|
122
|
+
|
|
123
|
+
Consumers should use stable event IDs and application-level idempotency when duplicate external side effects are unsafe.
|
|
124
|
+
|
|
125
|
+
## Backward compatibility
|
|
126
|
+
|
|
127
|
+
`0.2.12` is additive relative to `0.2.11`:
|
|
128
|
+
|
|
129
|
+
- existing `bcp/jobs` APIs remain unchanged,
|
|
130
|
+
- existing `bcp/workflow` APIs remain unchanged,
|
|
131
|
+
- no database adapter contract method was removed,
|
|
132
|
+
- existing applications do not need an outbox unless they opt into `bcp/events`.
|
|
133
|
+
|
|
134
|
+
## Validation
|
|
135
|
+
|
|
136
|
+
The release candidate must pass:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npm run typecheck
|
|
140
|
+
npm run test:unit
|
|
141
|
+
npm run test:integration
|
|
142
|
+
npm run test:e2e
|
|
143
|
+
npm run test:package
|
|
144
|
+
npm run rc:check
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Package validation executes the compiled `events.mjs` runtime and verifies the `bcp/events` export, transaction/outbox API, dispatcher delivery and migration helper.
|