@chidchanun/bcp 0.2.8 → 0.2.9
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 +75 -68
- package/docs/README.md +37 -132
- package/docs/api-manifest.json +3 -2
- package/docs/api-reference.md +36 -247
- package/docs/docs-web-manifest.json +5 -3
- package/docs/job-scheduling.md +357 -0
- package/docs/platform-manifest.json +12 -4
- package/docs/releases/0.2.9.md +162 -0
- package/package.json +2 -2
- package/packages/client/src/jobs.mjs +1040 -0
- package/packages/client/src/jobs.ts +17 -0
- package/packages/server/src/job-scheduler.ts +1144 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# Job Scheduling Platform
|
|
2
|
+
|
|
3
|
+
BCP Framework `0.2.9` extends the Background Jobs Platform with recurring job schedules, dependency-free UTC cron expressions, interval schedules and a schedule-store lease contract for multi-instance deployments.
|
|
4
|
+
|
|
5
|
+
Import scheduling APIs from the server-only `bcp/jobs` entrypoint:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import {
|
|
9
|
+
createJobQueue,
|
|
10
|
+
createJobScheduler,
|
|
11
|
+
} from "bcp/jobs";
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Create a scheduler
|
|
15
|
+
|
|
16
|
+
A scheduler enqueues work into an existing BCP background job queue:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import {
|
|
20
|
+
createJobQueue,
|
|
21
|
+
createJobScheduler,
|
|
22
|
+
} from "bcp/jobs";
|
|
23
|
+
|
|
24
|
+
export const jobs =
|
|
25
|
+
createJobQueue();
|
|
26
|
+
|
|
27
|
+
export const scheduler =
|
|
28
|
+
createJobScheduler({
|
|
29
|
+
queue: jobs,
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The scheduler does not execute application work itself. It creates normal queue jobs when a schedule becomes due; queue workers execute the registered job handlers.
|
|
34
|
+
|
|
35
|
+
## Interval schedules
|
|
36
|
+
|
|
37
|
+
Schedule a recurring job every five minutes:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
await scheduler.schedule(
|
|
41
|
+
"cache.cleanup",
|
|
42
|
+
{
|
|
43
|
+
scope: "expired",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "cache-cleanup",
|
|
47
|
+
everyMs: 5 * 60 * 1000,
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`everyMs` must be a positive integer.
|
|
53
|
+
|
|
54
|
+
By default the first run occurs one interval after the schedule is created.
|
|
55
|
+
|
|
56
|
+
Use `startAt` to select the first due time explicitly:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
await scheduler.schedule(
|
|
60
|
+
"report.daily",
|
|
61
|
+
{},
|
|
62
|
+
{
|
|
63
|
+
everyMs:
|
|
64
|
+
24 * 60 * 60 * 1000,
|
|
65
|
+
startAt:
|
|
66
|
+
Date.now() + 10_000,
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`startAt` accepts either a millisecond timestamp or a `Date`.
|
|
72
|
+
|
|
73
|
+
## Cron schedules
|
|
74
|
+
|
|
75
|
+
BCP `0.2.9` supports dependency-free five-field cron expressions:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
minute hour day-of-month month day-of-week
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Example — every weekday at 09:30 UTC:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
await scheduler.schedule(
|
|
85
|
+
"report.weekday",
|
|
86
|
+
{},
|
|
87
|
+
{
|
|
88
|
+
cron: "30 9 * * 1-5",
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Example — every 15 minutes:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
await scheduler.schedule(
|
|
97
|
+
"sync.incremental",
|
|
98
|
+
{},
|
|
99
|
+
{
|
|
100
|
+
cron: "*/15 * * * *",
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Supported field syntax:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
* every allowed value
|
|
109
|
+
*/n step
|
|
110
|
+
1,5,10 list
|
|
111
|
+
1-5 range
|
|
112
|
+
1-10/2 range with step
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Ranges:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
minute 0-59
|
|
119
|
+
hour 0-23
|
|
120
|
+
day-of-month 1-31
|
|
121
|
+
month 1-12
|
|
122
|
+
day-of-week 0-7 (0 and 7 are Sunday)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Cron evaluation is **UTC** in `0.2.9`. This avoids machine-local timezone differences between containers and servers.
|
|
126
|
+
|
|
127
|
+
When both day-of-month and day-of-week are restricted, BCP follows conventional cron OR semantics: either field may match.
|
|
128
|
+
|
|
129
|
+
Use `nextCronTime()` when application tooling needs to preview the next UTC occurrence:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import {
|
|
133
|
+
nextCronTime,
|
|
134
|
+
} from "bcp/jobs";
|
|
135
|
+
|
|
136
|
+
const next =
|
|
137
|
+
nextCronTime(
|
|
138
|
+
"0 2 * * *",
|
|
139
|
+
Date.now()
|
|
140
|
+
);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Run due schedules manually
|
|
144
|
+
|
|
145
|
+
`runDue()` is useful for deterministic tests or externally driven schedulers:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const count =
|
|
149
|
+
await scheduler.runDue();
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The return value is the number of newly enqueued jobs.
|
|
153
|
+
|
|
154
|
+
Options:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
await scheduler.runDue({
|
|
158
|
+
limit: 100,
|
|
159
|
+
leaseMs: 30_000,
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Each call claims at most one occurrence per due schedule. If an application was offline for many intervals, later calls may progressively catch up.
|
|
164
|
+
|
|
165
|
+
## Start a scheduler runner
|
|
166
|
+
|
|
167
|
+
For a long-running Node.js process:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const runner =
|
|
171
|
+
scheduler.start({
|
|
172
|
+
pollIntervalMs: 1_000,
|
|
173
|
+
leaseMs: 30_000,
|
|
174
|
+
limit: 100,
|
|
175
|
+
onError(error) {
|
|
176
|
+
console.error(
|
|
177
|
+
"scheduler failure",
|
|
178
|
+
error
|
|
179
|
+
);
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Graceful shutdown:
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
await runner.stop();
|
|
188
|
+
await scheduler.close();
|
|
189
|
+
await jobs.close();
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Stopping a scheduler does not close the queue automatically because applications may run queue workers independently.
|
|
193
|
+
|
|
194
|
+
## Schedule records
|
|
195
|
+
|
|
196
|
+
`JobScheduleRecord` includes:
|
|
197
|
+
|
|
198
|
+
```text
|
|
199
|
+
id
|
|
200
|
+
jobName
|
|
201
|
+
payload
|
|
202
|
+
schedule
|
|
203
|
+
createdAt
|
|
204
|
+
updatedAt
|
|
205
|
+
nextRunAt
|
|
206
|
+
lastRunAt
|
|
207
|
+
maxAttempts
|
|
208
|
+
leaseOwner
|
|
209
|
+
leaseUntil
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Inspect schedules:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
const schedules =
|
|
216
|
+
await scheduler.list();
|
|
217
|
+
|
|
218
|
+
const schedule =
|
|
219
|
+
await scheduler.get(
|
|
220
|
+
"cache-cleanup"
|
|
221
|
+
);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Remove one:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
await scheduler.remove(
|
|
228
|
+
"cache-cleanup"
|
|
229
|
+
);
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Calling `schedule()` with an existing schedule id is an upsert. Use stable ids for application-owned recurring schedules.
|
|
233
|
+
|
|
234
|
+
## Retry policy
|
|
235
|
+
|
|
236
|
+
A schedule may forward a queue retry limit:
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
await scheduler.schedule(
|
|
240
|
+
"billing.reconcile",
|
|
241
|
+
{},
|
|
242
|
+
{
|
|
243
|
+
cron: "0 * * * *",
|
|
244
|
+
maxAttempts: 5,
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Retry timing is still owned by `createJobQueue()`:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
const jobs =
|
|
253
|
+
createJobQueue({
|
|
254
|
+
retryDelayMs: attempt =>
|
|
255
|
+
attempt * 5_000,
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The scheduler determines **when a recurring occurrence is created**. The queue determines **how that occurrence is retried after handler failure**.
|
|
260
|
+
|
|
261
|
+
## Deterministic scheduled run IDs
|
|
262
|
+
|
|
263
|
+
Scheduled occurrences receive deterministic queue ids:
|
|
264
|
+
|
|
265
|
+
```text
|
|
266
|
+
schedule:<schedule-id>:<scheduled-for-timestamp>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
This provides an additional duplicate-enqueue defense if a scheduler retries the same occurrence.
|
|
270
|
+
|
|
271
|
+
Applications should avoid manually creating queue job ids with the `schedule:` prefix.
|
|
272
|
+
|
|
273
|
+
## Schedule store contract
|
|
274
|
+
|
|
275
|
+
The built-in schedule store is process-local:
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import {
|
|
279
|
+
createMemoryJobScheduleStore,
|
|
280
|
+
} from "bcp/jobs";
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
It is useful for development, tests and single-process applications.
|
|
284
|
+
|
|
285
|
+
Production deployments that run multiple scheduler processes or must preserve schedules across restarts should implement `JobScheduleStore` using shared durable infrastructure.
|
|
286
|
+
|
|
287
|
+
Required operations:
|
|
288
|
+
|
|
289
|
+
```text
|
|
290
|
+
upsert
|
|
291
|
+
get
|
|
292
|
+
list
|
|
293
|
+
remove
|
|
294
|
+
acquireDue
|
|
295
|
+
complete
|
|
296
|
+
release
|
|
297
|
+
close (optional)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`acquireDue()` is the critical concurrency boundary. A durable implementation should atomically claim due schedules and assign a lease owner/expiry so two scheduler instances do not both own the same occurrence.
|
|
301
|
+
|
|
302
|
+
Conceptually:
|
|
303
|
+
|
|
304
|
+
```text
|
|
305
|
+
scheduler A ─┐
|
|
306
|
+
├─ shared JobScheduleStore ── atomic acquireDue()
|
|
307
|
+
scheduler B ─┘
|
|
308
|
+
│
|
|
309
|
+
▼
|
|
310
|
+
shared/durable queue
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Examples of possible application adapters include PostgreSQL, Redis, DynamoDB or another transactional/atomic data store. `0.2.9` intentionally does not force one provider.
|
|
314
|
+
|
|
315
|
+
## Lease behavior
|
|
316
|
+
|
|
317
|
+
A scheduler runner identifies itself with `ownerId`:
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
const scheduler =
|
|
321
|
+
createJobScheduler({
|
|
322
|
+
queue: jobs,
|
|
323
|
+
store,
|
|
324
|
+
ownerId:
|
|
325
|
+
process.env.INSTANCE_ID,
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
If `ownerId` is omitted, BCP generates a unique process-local scheduler id.
|
|
330
|
+
|
|
331
|
+
A due schedule is leased for `leaseMs`. The store releases the lease after the occurrence is committed. If a scheduler dies while holding a lease, another instance may reclaim it after lease expiry.
|
|
332
|
+
|
|
333
|
+
For durable adapters, choose a lease duration longer than the expected enqueue/store round trip but short enough for acceptable recovery.
|
|
334
|
+
|
|
335
|
+
## Queue durability remains separate
|
|
336
|
+
|
|
337
|
+
A durable schedule store does not make the queue durable by itself.
|
|
338
|
+
|
|
339
|
+
For multi-instance production you will normally need both:
|
|
340
|
+
|
|
341
|
+
```text
|
|
342
|
+
shared JobScheduleStore
|
|
343
|
+
+
|
|
344
|
+
shared JobQueueAdapter
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
The built-in memory schedule store and memory queue are intentionally process-local.
|
|
348
|
+
|
|
349
|
+
## Server-only boundary
|
|
350
|
+
|
|
351
|
+
`bcp/jobs` is server-only. Do not import it from page components, client islands or other modules reachable from browser bundles.
|
|
352
|
+
|
|
353
|
+
Use job/scheduler calls from server routes, loaders/actions, server startup modules or dedicated worker processes.
|
|
354
|
+
|
|
355
|
+
## Compatibility
|
|
356
|
+
|
|
357
|
+
`0.2.9` does not intentionally break `0.2.8` Background Jobs APIs. Existing queue/worker code remains valid; scheduling is additive.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"framework": "bcp",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.9",
|
|
5
5
|
"releaseState": "unreleased",
|
|
6
|
-
"baseline": "
|
|
6
|
+
"baseline": "job-scheduling-platform",
|
|
7
7
|
"runtime": {
|
|
8
8
|
"node": ">=24.11.0",
|
|
9
9
|
"react": "19",
|
|
@@ -73,6 +73,13 @@
|
|
|
73
73
|
"jobRetries": true,
|
|
74
74
|
"jobWorkerConcurrency": true,
|
|
75
75
|
"jobCancellation": true,
|
|
76
|
+
"jobSchedulingPlatform": true,
|
|
77
|
+
"recurringJobs": true,
|
|
78
|
+
"cronScheduling": true,
|
|
79
|
+
"intervalScheduling": true,
|
|
80
|
+
"jobScheduleStoreContract": true,
|
|
81
|
+
"schedulerLeases": true,
|
|
82
|
+
"scheduledRunDeduplication": true,
|
|
76
83
|
"databaseMigrations": true,
|
|
77
84
|
"databaseAdapterContract": true,
|
|
78
85
|
"databasePostgresql": true,
|
|
@@ -112,7 +119,7 @@
|
|
|
112
119
|
"s3-compatible"
|
|
113
120
|
],
|
|
114
121
|
"compatibility": {
|
|
115
|
-
"previousBaseline": "0.2.
|
|
122
|
+
"previousBaseline": "0.2.8",
|
|
116
123
|
"intentionalBreakingChangesFromPreviousBaseline": false,
|
|
117
124
|
"migrationGuide": "migration-0.2.md"
|
|
118
125
|
},
|
|
@@ -130,7 +137,8 @@
|
|
|
130
137
|
"authorizationSecurity": "authorization-security.md",
|
|
131
138
|
"observability": "observability.md",
|
|
132
139
|
"backgroundJobs": "background-jobs.md",
|
|
140
|
+
"jobScheduling": "job-scheduling.md",
|
|
133
141
|
"migrationGuide": "migration-0.2.md",
|
|
134
|
-
"releaseNotes": "releases/0.2.
|
|
142
|
+
"releaseNotes": "releases/0.2.9.md"
|
|
135
143
|
}
|
|
136
144
|
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# BCP Framework 0.2.9 — Job Scheduling Platform
|
|
2
|
+
|
|
3
|
+
> Release state: unreleased until the complete RC workflow passes, the release commit is tagged `v0.2.9`, and npm publication completes.
|
|
4
|
+
|
|
5
|
+
BCP Framework `0.2.9` extends the `0.2.8` Background Jobs Platform with recurring schedules, dependency-free UTC cron expressions and a lease-aware schedule-store contract.
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- Added `createJobScheduler()` through `bcp/jobs`.
|
|
10
|
+
- Added interval-based recurring jobs with `everyMs`.
|
|
11
|
+
- Added five-field UTC cron expressions.
|
|
12
|
+
- Added `nextCronTime()` and `nextScheduleTime()` helpers.
|
|
13
|
+
- Added `JobScheduleStore` for durable/shared scheduler state.
|
|
14
|
+
- Added `createMemoryJobScheduleStore()` for local development and tests.
|
|
15
|
+
- Added atomic-style `acquireDue()` lease semantics to the schedule-store contract.
|
|
16
|
+
- Added deterministic scheduled queue ids to reduce duplicate enqueue risk.
|
|
17
|
+
- Added scheduler polling lifecycle with `start()`, `stop()` and `close()`.
|
|
18
|
+
- Added schedule inspection, removal and stable-id upsert behavior.
|
|
19
|
+
- Added unit, package-smoke and platform-contract coverage.
|
|
20
|
+
|
|
21
|
+
## Scheduling API
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import {
|
|
25
|
+
createJobQueue,
|
|
26
|
+
createJobScheduler,
|
|
27
|
+
} from "bcp/jobs";
|
|
28
|
+
|
|
29
|
+
const jobs =
|
|
30
|
+
createJobQueue();
|
|
31
|
+
|
|
32
|
+
const scheduler =
|
|
33
|
+
createJobScheduler({
|
|
34
|
+
queue: jobs,
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Interval:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
await scheduler.schedule(
|
|
42
|
+
"cache.cleanup",
|
|
43
|
+
{},
|
|
44
|
+
{
|
|
45
|
+
id: "cache-cleanup",
|
|
46
|
+
everyMs: 300_000,
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Cron:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
await scheduler.schedule(
|
|
55
|
+
"report.weekday",
|
|
56
|
+
{},
|
|
57
|
+
{
|
|
58
|
+
cron: "30 9 * * 1-5",
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Cron evaluation is UTC in `0.2.9`.
|
|
64
|
+
|
|
65
|
+
## Cron syntax
|
|
66
|
+
|
|
67
|
+
Five fields are supported:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
minute hour day-of-month month day-of-week
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Supported tokens:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
*
|
|
77
|
+
*/n
|
|
78
|
+
comma-separated values
|
|
79
|
+
ranges
|
|
80
|
+
range steps
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Day of week accepts `0` and `7` for Sunday. When both day-of-month and day-of-week are restricted, standard cron OR semantics are used.
|
|
84
|
+
|
|
85
|
+
## Scheduler lifecycle
|
|
86
|
+
|
|
87
|
+
Long-running scheduler:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const runner =
|
|
91
|
+
scheduler.start({
|
|
92
|
+
pollIntervalMs: 1_000,
|
|
93
|
+
leaseMs: 30_000,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// shutdown
|
|
97
|
+
await runner.stop();
|
|
98
|
+
await scheduler.close();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`runDue()` is also available for tests, external control loops and deterministic execution.
|
|
102
|
+
|
|
103
|
+
## Multi-instance contract
|
|
104
|
+
|
|
105
|
+
`JobScheduleStore.acquireDue()` is the scheduler concurrency boundary. Durable implementations should atomically claim due schedules with a lease owner and expiry.
|
|
106
|
+
|
|
107
|
+
The default memory store is process-local and is not suitable for schedules that must survive restarts or coordinate across multiple containers.
|
|
108
|
+
|
|
109
|
+
Production multi-instance systems will normally pair:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
shared JobScheduleStore
|
|
113
|
+
+
|
|
114
|
+
shared JobQueueAdapter
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`0.2.9` intentionally leaves provider choice to the application instead of forcing Redis, PostgreSQL or another queue/scheduler backend.
|
|
118
|
+
|
|
119
|
+
## Duplicate protection
|
|
120
|
+
|
|
121
|
+
Each scheduled occurrence uses a deterministic queue id:
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
schedule:<schedule-id>:<scheduled-for-timestamp>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This complements store leasing and protects the built-in queue from enqueuing the same occurrence twice if the same schedule occurrence is retried.
|
|
128
|
+
|
|
129
|
+
## Compatibility
|
|
130
|
+
|
|
131
|
+
This milestone is additive. There are no intentional breaking changes from `0.2.8`.
|
|
132
|
+
|
|
133
|
+
Existing `createJobQueue()`, handlers, delayed jobs, retries, workers and adapters continue to work without scheduling enabled.
|
|
134
|
+
|
|
135
|
+
## Documentation
|
|
136
|
+
|
|
137
|
+
New guide:
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
docs/job-scheduling.md
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Background jobs remain documented in:
|
|
144
|
+
|
|
145
|
+
```text
|
|
146
|
+
docs/background-jobs.md
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Validation
|
|
150
|
+
|
|
151
|
+
Before tagging/publishing `0.2.9`, run:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm run typecheck
|
|
155
|
+
npm run test:unit
|
|
156
|
+
npm run test:integration
|
|
157
|
+
npm run test:e2e
|
|
158
|
+
npm run test:package
|
|
159
|
+
npm run rc:check
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The release tag must point to the exact commit that passed the complete RC sequence.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chidchanun/bcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "BCP Framework - a React full-stack framework with file-based routing, SSR, APIs, middleware, islands, caching and standalone production builds.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"./jobs": {
|
|
66
66
|
"types": "./packages/client/src/jobs.ts",
|
|
67
67
|
"browser": "./packages/client/src/server-only.browser.mjs",
|
|
68
|
-
"default": "./packages/client/src/jobs.
|
|
68
|
+
"default": "./packages/client/src/jobs.mjs"
|
|
69
69
|
},
|
|
70
70
|
"./observability": {
|
|
71
71
|
"types": "./packages/client/src/observability.ts",
|