nuxt-cf-jobs 0.14.2 → 0.14.3
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
CHANGED
|
@@ -221,7 +221,7 @@ const route = getJobDefinition(name)
|
|
|
221
221
|
const fullDefinition = await loadJobDefinition(name)
|
|
222
222
|
```
|
|
223
223
|
|
|
224
|
-
`getJobDefinition()`
|
|
224
|
+
`getJobDefinition()` returns static routing and literal policy metadata without loading the job module. It does not include executable fields such as `handle`, `input`, or `uniqueId`. Use `loadJobDefinition()` when you need the full definition. The durable `prepareJob()` helper does this automatically. Jobs with `broadcast` also generate `JobBroadcastMessage<Name>` and `JobBroadcastEnvelope<Name>` types.
|
|
225
225
|
|
|
226
226
|
Runtime validation is available when you want to fail a custom startup check:
|
|
227
227
|
|
|
@@ -357,7 +357,7 @@ export default defineEventHandler(async (event) => {
|
|
|
357
357
|
- `not-dispatched`: the row is safe in D1, but the queue binding was unavailable.
|
|
358
358
|
- `dispatch-failed`: the row is safe in D1, and `cause` contains the send error.
|
|
359
359
|
|
|
360
|
-
The generated `prepareJob()` validates the payload, resolves the queue, applies attempts and uniqueness, and checks the
|
|
360
|
+
The generated `prepareJob()` loads the full job definition, validates the payload, resolves the queue, applies attempts and uniqueness, and checks the serialized payload against the durable D1 storage limit before inserting anything.
|
|
361
361
|
|
|
362
362
|
### Recovery
|
|
363
363
|
|
package/dist/module.json
CHANGED
|
@@ -59,7 +59,7 @@ export const jobErrors = {
|
|
|
59
59
|
task,
|
|
60
60
|
bytes,
|
|
61
61
|
limit,
|
|
62
|
-
message: `Job payload exceeds
|
|
62
|
+
message: `Job payload exceeds durable storage limit of ${limit} bytes for task: ${task}`
|
|
63
63
|
};
|
|
64
64
|
},
|
|
65
65
|
noRoute(task) {
|
|
@@ -3,6 +3,14 @@ import type { SendBackpressureOptions } from './queue.js';
|
|
|
3
3
|
import type { AnyJobDefinition, JobNameOf, JobPayloadByName, JobQueueByName } from './registry.js';
|
|
4
4
|
import type { Result } from './result.js';
|
|
5
5
|
import type { DispatchableJob, DispatchResult, JobContext, JobControlResult, JobDefinition, JobHandler, QueueMessage, QueueSendOptions } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Maximum serialized durable payload size.
|
|
8
|
+
*
|
|
9
|
+
* Durable payloads live in D1. Queue messages only carry `{ jobId, queue }`, so
|
|
10
|
+
* the Cloudflare Queue message limit does not apply here. This leaves 100,000
|
|
11
|
+
* bytes below D1's 2,000,000-byte row limit for storage overhead.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DURABLE_JOB_MAX_PAYLOAD_BYTES = 1900000;
|
|
6
14
|
export interface DurableJobRoute<Queue extends string = string> {
|
|
7
15
|
queue: Queue;
|
|
8
16
|
jobType: string;
|
|
@@ -77,8 +85,13 @@ export interface DurableJobFailureRepository {
|
|
|
77
85
|
recordFailure: (input: RecordDurableJobFailureInput) => Promise<void>;
|
|
78
86
|
}
|
|
79
87
|
export interface DurableJobRegistryLike<Env = unknown, Db = unknown, Logger = unknown> {
|
|
80
|
-
/** May resolve asynchronously for lazily-loaded jobs.
|
|
88
|
+
/** May resolve asynchronously for lazily-loaded jobs. */
|
|
81
89
|
getHandler?: (name: string) => JobHandler<unknown, Env, Db, Logger> | undefined | Promise<JobHandler<unknown, Env, Db, Logger> | undefined>;
|
|
90
|
+
/**
|
|
91
|
+
* Loads the full definition when producer policy depends on executable fields
|
|
92
|
+
* such as `input` or `uniqueId`.
|
|
93
|
+
*/
|
|
94
|
+
loadJobDefinition?: (name: string) => Promise<JobDefinition<string, unknown, string, Env, Db, Logger> | undefined>;
|
|
82
95
|
getJobDefinition?: (name: string) => JobDefinition<string, unknown, string, Env, Db, Logger> | undefined;
|
|
83
96
|
getJobRoute?: (name: string) => DurableJobRoute<string> | undefined;
|
|
84
97
|
}
|
|
@@ -2,12 +2,13 @@ import { dispatchRegisteredJob } from "./dispatch.js";
|
|
|
2
2
|
import { describeCause, describeCauseWithStack, formatJobError, isDurableJobOwnershipError, jobErrors, jobErrorToException } from "./errors.js";
|
|
3
3
|
import { buildJobPayload } from "./payload.js";
|
|
4
4
|
import { createJobTraceId, createJobUniqueKey, resolveJobMaxAttempts } from "./policy.js";
|
|
5
|
-
import {
|
|
5
|
+
import { sendBatchChunked, withSendBackpressure } from "./queue.js";
|
|
6
6
|
import { parseJobInput } from "./registry.js";
|
|
7
7
|
import { err, ok, unwrapResult } from "./result.js";
|
|
8
8
|
function byteLength(value) {
|
|
9
9
|
return typeof Buffer !== "undefined" ? Buffer.byteLength(value, "utf8") : new TextEncoder().encode(value).byteLength;
|
|
10
10
|
}
|
|
11
|
+
export const DURABLE_JOB_MAX_PAYLOAD_BYTES = 19e5;
|
|
11
12
|
export async function pruneDurableJobs(repository, opts) {
|
|
12
13
|
const completedJobs = typeof opts.completedBefore === "number" ? await repository.pruneCompletedJobs({ before: opts.completedBefore, limit: opts.limit }) : 0;
|
|
13
14
|
const failedJobs = typeof opts.failedBefore === "number" ? await repository.pruneFailedJobs({ before: opts.failedBefore, limit: opts.limit }) : 0;
|
|
@@ -31,8 +32,8 @@ export async function prepareDurableJobResult(opts) {
|
|
|
31
32
|
const payload = buildJobPayload(opts.name, parsedPayload.data);
|
|
32
33
|
const serialized = JSON.stringify(continuations ? { ...payload, _continuations: continuations } : payload);
|
|
33
34
|
const bytes = byteLength(serialized);
|
|
34
|
-
if (bytes >
|
|
35
|
-
return err(jobErrors.payloadTooLarge(opts.name, bytes,
|
|
35
|
+
if (bytes > DURABLE_JOB_MAX_PAYLOAD_BYTES)
|
|
36
|
+
return err(jobErrors.payloadTooLarge(opts.name, bytes, DURABLE_JOB_MAX_PAYLOAD_BYTES));
|
|
36
37
|
return ok({
|
|
37
38
|
id: opts.id ?? crypto.randomUUID(),
|
|
38
39
|
queue: route.queue,
|
|
@@ -54,9 +55,11 @@ export async function prepareDurableJob(opts) {
|
|
|
54
55
|
return unwrapResult(await prepareDurableJobResult(opts), jobErrorToException);
|
|
55
56
|
}
|
|
56
57
|
export async function prepareRegisteredDurableJob(registry, opts) {
|
|
58
|
+
const definition = registry.loadJobDefinition ? await registry.loadJobDefinition(opts.name) : registry.getJobDefinition?.(opts.name);
|
|
57
59
|
return prepareDurableJob({
|
|
58
60
|
...opts,
|
|
59
|
-
registry
|
|
61
|
+
registry,
|
|
62
|
+
definition
|
|
60
63
|
});
|
|
61
64
|
}
|
|
62
65
|
function resolveDurableJobRoute(name, route, definition, registry) {
|
|
@@ -28,10 +28,9 @@ interface DefineJobBaseOptions<Name extends string, Payload extends object, Queu
|
|
|
28
28
|
* A build-time registry entry that defers loading the handler module. The
|
|
29
29
|
* static routing fields are AST-extracted from the job's `defineJob({...})`
|
|
30
30
|
* call so the producer/consumer can route, validate queues and resolve attempts
|
|
31
|
-
* WITHOUT importing (and evaluating) the handler
|
|
32
|
-
* definition
|
|
33
|
-
*
|
|
34
|
-
* worker from evaluating all job modules to run one job.
|
|
31
|
+
* WITHOUT importing (and evaluating) the handler. `load()` pulls the full
|
|
32
|
+
* definition for dispatch and durable producer preparation. This keeps a worker
|
|
33
|
+
* from evaluating every job module to run or prepare one job.
|
|
35
34
|
*/
|
|
36
35
|
export interface LazyJobEntry<Name extends string = string, Queue extends string = string> {
|
|
37
36
|
name: Name;
|