glasswork 0.12.1 → 0.13.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/dist/auth/abilities.d.ts +41 -0
- package/dist/auth/abilities.d.ts.map +1 -0
- package/dist/auth/abilities.js +62 -0
- package/dist/auth/abilities.js.map +1 -0
- package/dist/auth/assert.d.ts +20 -0
- package/dist/auth/assert.d.ts.map +1 -0
- package/dist/auth/assert.js +28 -0
- package/dist/auth/assert.js.map +1 -0
- package/dist/auth/better-auth-provider.d.ts +56 -0
- package/dist/auth/better-auth-provider.d.ts.map +1 -0
- package/dist/auth/better-auth-provider.js +62 -0
- package/dist/auth/better-auth-provider.js.map +1 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/middleware.d.ts +31 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +92 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/types.d.ts +54 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/core/bootstrap.d.ts.map +1 -1
- package/dist/core/bootstrap.js +5 -2
- package/dist/core/bootstrap.js.map +1 -1
- package/dist/core/types.d.ts +14 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/http/route-helpers.d.ts +47 -9
- package/dist/http/route-helpers.d.ts.map +1 -1
- package/dist/http/route-helpers.js +91 -40
- package/dist/http/route-helpers.js.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/jobs/define-job.d.ts +57 -0
- package/dist/jobs/define-job.d.ts.map +1 -0
- package/dist/jobs/define-job.js +12 -0
- package/dist/jobs/define-job.js.map +1 -0
- package/dist/jobs/drivers/eventbridge-scheduler-driver.d.ts +75 -0
- package/dist/jobs/drivers/eventbridge-scheduler-driver.d.ts.map +1 -0
- package/dist/jobs/drivers/eventbridge-scheduler-driver.js +135 -0
- package/dist/jobs/drivers/eventbridge-scheduler-driver.js.map +1 -0
- package/dist/jobs/drivers/mock-driver.d.ts +73 -0
- package/dist/jobs/drivers/mock-driver.d.ts.map +1 -0
- package/dist/jobs/drivers/mock-driver.js +95 -0
- package/dist/jobs/drivers/mock-driver.js.map +1 -0
- package/dist/jobs/drivers/sqs-driver.d.ts +59 -0
- package/dist/jobs/drivers/sqs-driver.d.ts.map +1 -0
- package/dist/jobs/drivers/sqs-driver.js +176 -0
- package/dist/jobs/drivers/sqs-driver.js.map +1 -0
- package/dist/jobs/errors.d.ts +44 -0
- package/dist/jobs/errors.d.ts.map +1 -0
- package/dist/jobs/errors.js +67 -0
- package/dist/jobs/errors.js.map +1 -0
- package/dist/jobs/index.d.ts +12 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +11 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/job-registry.d.ts +33 -0
- package/dist/jobs/job-registry.d.ts.map +1 -0
- package/dist/jobs/job-registry.js +56 -0
- package/dist/jobs/job-registry.js.map +1 -0
- package/dist/jobs/job-service.d.ts +44 -0
- package/dist/jobs/job-service.d.ts.map +1 -0
- package/dist/jobs/job-service.js +105 -0
- package/dist/jobs/job-service.js.map +1 -0
- package/dist/jobs/periodic-job.d.ts +6 -0
- package/dist/jobs/periodic-job.d.ts.map +1 -0
- package/dist/jobs/periodic-job.js +11 -0
- package/dist/jobs/periodic-job.js.map +1 -0
- package/dist/jobs/schedule-constants.d.ts +5 -0
- package/dist/jobs/schedule-constants.d.ts.map +1 -0
- package/dist/jobs/schedule-constants.js +5 -0
- package/dist/jobs/schedule-constants.js.map +1 -0
- package/dist/jobs/scheduler.d.ts +17 -0
- package/dist/jobs/scheduler.d.ts.map +1 -0
- package/dist/jobs/scheduler.js +83 -0
- package/dist/jobs/scheduler.js.map +1 -0
- package/dist/jobs/types.d.ts +165 -0
- package/dist/jobs/types.d.ts.map +1 -0
- package/dist/jobs/types.js +2 -0
- package/dist/jobs/types.js.map +1 -0
- package/dist/jobs/utils.d.ts +15 -0
- package/dist/jobs/utils.d.ts.map +1 -0
- package/dist/jobs/utils.js +49 -0
- package/dist/jobs/utils.js.map +1 -0
- package/dist/jobs/worker.d.ts +35 -0
- package/dist/jobs/worker.d.ts.map +1 -0
- package/dist/jobs/worker.js +361 -0
- package/dist/jobs/worker.js.map +1 -0
- package/dist/list-query/casl.d.ts +18 -19
- package/dist/list-query/casl.d.ts.map +1 -1
- package/dist/list-query/casl.js +40 -46
- package/dist/list-query/casl.js.map +1 -1
- package/dist/uploads/file-upload.d.ts +44 -0
- package/dist/uploads/file-upload.d.ts.map +1 -0
- package/dist/uploads/file-upload.js +145 -0
- package/dist/uploads/file-upload.js.map +1 -0
- package/dist/uploads/index.d.ts +6 -0
- package/dist/uploads/index.d.ts.map +1 -0
- package/dist/uploads/index.js +7 -0
- package/dist/uploads/index.js.map +1 -0
- package/dist/uploads/uploads.service.d.ts +98 -0
- package/dist/uploads/uploads.service.d.ts.map +1 -0
- package/dist/uploads/uploads.service.js +134 -0
- package/dist/uploads/uploads.service.js.map +1 -0
- package/dist/uploads/validators.d.ts +41 -0
- package/dist/uploads/validators.d.ts.map +1 -0
- package/dist/uploads/validators.js +94 -0
- package/dist/uploads/validators.js.map +1 -0
- package/package.json +34 -3
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { BaseIssue, BaseSchema } from 'valibot';
|
|
2
|
+
import type { Logger } from '../utils/logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Duration expressed as human-readable string (e.g. "5m") or seconds as number.
|
|
5
|
+
*/
|
|
6
|
+
export type Duration = string | number;
|
|
7
|
+
/**
|
|
8
|
+
* Retry configuration for jobs.
|
|
9
|
+
*
|
|
10
|
+
* Glasswork relies on SQS visibility timeout for retry timing, but this
|
|
11
|
+
* configuration influences how the worker handles failures and determines
|
|
12
|
+
* when a job should be considered "dead" (retries exhausted).
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Default: 25 retries, send to DLQ
|
|
17
|
+
* defineJob({ name: 'my-job', handler: ... })
|
|
18
|
+
*
|
|
19
|
+
* // Custom retry count
|
|
20
|
+
* defineJob({ name: 'my-job', retry: { maxAttempts: 5 }, handler: ... })
|
|
21
|
+
*
|
|
22
|
+
* // No retries, discard on failure
|
|
23
|
+
* defineJob({ name: 'my-job', retry: false, handler: ... })
|
|
24
|
+
*
|
|
25
|
+
* // Retry but don't save to DLQ
|
|
26
|
+
* defineJob({ name: 'my-job', retry: { maxAttempts: 10, dead: false }, handler: ... })
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export interface RetryConfig {
|
|
30
|
+
/**
|
|
31
|
+
* Maximum number of retries before the job is considered dead.
|
|
32
|
+
* The default is 25 retries.
|
|
33
|
+
*
|
|
34
|
+
* @default 25
|
|
35
|
+
*/
|
|
36
|
+
maxAttempts?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Whether to save failed jobs to the dead letter queue after exhausting retries.
|
|
39
|
+
* If false, jobs will be discarded (not re-thrown to SQS) after max attempts.
|
|
40
|
+
*
|
|
41
|
+
* @default true
|
|
42
|
+
*/
|
|
43
|
+
dead?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Execution context passed to job handlers.
|
|
47
|
+
*/
|
|
48
|
+
export interface JobContext {
|
|
49
|
+
/** DI container services (shaped by user module) */
|
|
50
|
+
services: Record<string, unknown>;
|
|
51
|
+
/** Job identifier */
|
|
52
|
+
jobId: string;
|
|
53
|
+
/** Current attempt number (starts at 1) */
|
|
54
|
+
attemptNumber: number;
|
|
55
|
+
/** Timestamp when the job was enqueued */
|
|
56
|
+
enqueuedAt: Date;
|
|
57
|
+
/** Optional logger scoped to the job */
|
|
58
|
+
logger?: Logger;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Job handler signature.
|
|
62
|
+
*/
|
|
63
|
+
export type JobHandler<TPayload> = (payload: TPayload, context: JobContext) => Promise<void> | void;
|
|
64
|
+
/**
|
|
65
|
+
* Job definition with optional schema validation and retry configuration.
|
|
66
|
+
*/
|
|
67
|
+
export interface JobDefinition<TPayload> {
|
|
68
|
+
/** Unique job name */
|
|
69
|
+
name: string;
|
|
70
|
+
/** Target queue (default resolved by JobService) */
|
|
71
|
+
queue?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Dead-letter queue name for operational documentation.
|
|
74
|
+
* Configure the actual DLQ/redrive policy in your queue infrastructure
|
|
75
|
+
* (e.g., SQS redrive policy pointing the primary queue to this DLQ).
|
|
76
|
+
*/
|
|
77
|
+
deadLetterQueue?: string;
|
|
78
|
+
/** Optional payload schema for validation */
|
|
79
|
+
schema?: BaseSchema<TPayload, TPayload, BaseIssue<unknown>>;
|
|
80
|
+
/**
|
|
81
|
+
* Retry configuration for this job.
|
|
82
|
+
*
|
|
83
|
+
* - `undefined`: Default (25 retries, send to DLQ)
|
|
84
|
+
* - `number`: Shorthand for { maxAttempts: N }
|
|
85
|
+
* - `false`: Disable retries (discard on first failure)
|
|
86
|
+
* - `RetryConfig`: Full configuration object
|
|
87
|
+
*/
|
|
88
|
+
retry?: RetryConfig | number | false;
|
|
89
|
+
/**
|
|
90
|
+
* Optional uniqueness constraint. Intended for FIFO queues.
|
|
91
|
+
* The deduplication key should be stable for the same logical job.
|
|
92
|
+
*/
|
|
93
|
+
unique?: {
|
|
94
|
+
key: (payload: TPayload) => string;
|
|
95
|
+
/** Deduplication window (advisory; FIFO queues cap at 5 minutes) */
|
|
96
|
+
window?: Duration;
|
|
97
|
+
};
|
|
98
|
+
/** Handler invoked by the worker */
|
|
99
|
+
handler: JobHandler<TPayload>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Type-erased job definition for use in module registration.
|
|
103
|
+
*
|
|
104
|
+
* Use this type when registering jobs in modules to avoid the awkward
|
|
105
|
+
* `as JobDefinition<unknown>` cast. This works because module registration
|
|
106
|
+
* only needs to access the `name` property and invoke the handler dynamically.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* // In your module:
|
|
111
|
+
* export const MyModule = defineModule({
|
|
112
|
+
* jobs: [myJob], // No cast needed!
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export type AnyJobDefinition = JobDefinition<any>;
|
|
117
|
+
/**
|
|
118
|
+
* Job message sent to a queue.
|
|
119
|
+
*/
|
|
120
|
+
export interface JobMessage {
|
|
121
|
+
/** Job type identifier */
|
|
122
|
+
jobName: string;
|
|
123
|
+
/** Serialized job payload */
|
|
124
|
+
payload: unknown;
|
|
125
|
+
/** Queue to use (default resolved by JobService/driver) */
|
|
126
|
+
queue?: string;
|
|
127
|
+
/** Optional client-provided job ID */
|
|
128
|
+
jobId?: string;
|
|
129
|
+
/** Additional metadata */
|
|
130
|
+
metadata?: Record<string, string>;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Result returned after enqueuing a job.
|
|
134
|
+
*/
|
|
135
|
+
export interface EnqueueResult {
|
|
136
|
+
/** Queue-assigned message ID */
|
|
137
|
+
messageId: string;
|
|
138
|
+
/** Generated or provided job ID */
|
|
139
|
+
jobId: string;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Queue driver interface.
|
|
143
|
+
*
|
|
144
|
+
* Methods beyond `enqueue` are placeholders for later phases and may throw
|
|
145
|
+
* until implemented by a driver.
|
|
146
|
+
*/
|
|
147
|
+
export interface QueueDriver {
|
|
148
|
+
/** Driver name for logging/debugging */
|
|
149
|
+
readonly name: string;
|
|
150
|
+
/** Default queue name resolved by the driver (optional) */
|
|
151
|
+
readonly defaultQueue?: string;
|
|
152
|
+
/**
|
|
153
|
+
* Enqueue a job for immediate processing.
|
|
154
|
+
*/
|
|
155
|
+
enqueue(message: JobMessage): Promise<EnqueueResult>;
|
|
156
|
+
/**
|
|
157
|
+
* Enqueue a job for processing at a specific time.
|
|
158
|
+
*/
|
|
159
|
+
enqueueAt?(message: JobMessage, at: Date): Promise<EnqueueResult>;
|
|
160
|
+
/**
|
|
161
|
+
* Enqueue a job for processing after a delay.
|
|
162
|
+
*/
|
|
163
|
+
enqueueIn?(message: JobMessage, delay: Duration): Promise<EnqueueResult>;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/jobs/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/jobs/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Duration } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a unique job identifier.
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateJobId(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Calculate the size of a payload once serialized.
|
|
8
|
+
*/
|
|
9
|
+
export declare function calculatePayloadSizeBytes(payload: unknown): number;
|
|
10
|
+
/**
|
|
11
|
+
* Parse a duration value into seconds.
|
|
12
|
+
* Supports number (seconds) or string like "5m", "30s", "1h", "1d".
|
|
13
|
+
*/
|
|
14
|
+
export declare function durationToSeconds(duration: Duration): number;
|
|
15
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/jobs/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAKlE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CA2B5D"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a unique job identifier.
|
|
4
|
+
*/
|
|
5
|
+
export function generateJobId() {
|
|
6
|
+
if (typeof randomUUID === 'function') {
|
|
7
|
+
return randomUUID();
|
|
8
|
+
}
|
|
9
|
+
return `job-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Calculate the size of a payload once serialized.
|
|
13
|
+
*/
|
|
14
|
+
export function calculatePayloadSizeBytes(payload) {
|
|
15
|
+
// JSON.stringify(undefined) returns undefined, not a string
|
|
16
|
+
const serialized = payload === undefined ? 'null' : JSON.stringify(payload);
|
|
17
|
+
const encoded = new TextEncoder().encode(serialized);
|
|
18
|
+
return encoded.length;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse a duration value into seconds.
|
|
22
|
+
* Supports number (seconds) or string like "5m", "30s", "1h", "1d".
|
|
23
|
+
*/
|
|
24
|
+
export function durationToSeconds(duration) {
|
|
25
|
+
if (typeof duration === 'number') {
|
|
26
|
+
return duration;
|
|
27
|
+
}
|
|
28
|
+
const trimmed = duration.trim();
|
|
29
|
+
const match = /^(\d+(?:\.\d+)?)([smhd]?)$/i.exec(trimmed);
|
|
30
|
+
if (!match) {
|
|
31
|
+
throw new Error(`Invalid duration format: "${duration}"`);
|
|
32
|
+
}
|
|
33
|
+
const value = Number.parseFloat(match[1]);
|
|
34
|
+
const unit = match[2].toLowerCase();
|
|
35
|
+
switch (unit) {
|
|
36
|
+
case 's':
|
|
37
|
+
case '':
|
|
38
|
+
return value;
|
|
39
|
+
case 'm':
|
|
40
|
+
return value * 60;
|
|
41
|
+
case 'h':
|
|
42
|
+
return value * 60 * 60;
|
|
43
|
+
case 'd':
|
|
44
|
+
return value * 60 * 60 * 24;
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`Unsupported duration unit: "${unit}"`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/jobs/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;QACrC,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IACD,OAAO,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAgB;IACxD,4DAA4D;IAC5D,MAAM,UAAU,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC5E,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACrD,OAAO,OAAO,CAAC,MAAM,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAkB;IAClD,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,6BAA6B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAEpC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,GAAG,CAAC;QACT,KAAK,EAAE;YACL,OAAO,KAAK,CAAC;QACf,KAAK,GAAG;YACN,OAAO,KAAK,GAAG,EAAE,CAAC;QACpB,KAAK,GAAG;YACN,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,CAAC;QACzB,KAAK,GAAG;YACN,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QAC9B;YACE,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,GAAG,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Context, EventBridgeEvent, SQSEvent } from 'aws-lambda';
|
|
2
|
+
import type { ModuleConfig } from '../core/types.js';
|
|
3
|
+
import { type Logger } from '../utils/logger.js';
|
|
4
|
+
import type { JobContext } from './types.js';
|
|
5
|
+
interface WorkerHooks {
|
|
6
|
+
onJobStart?: (job: JobExecution, context: JobContext) => Promise<void> | void;
|
|
7
|
+
onJobComplete?: (job: JobExecution, context: JobContext) => Promise<void> | void;
|
|
8
|
+
onJobFailed?: (job: JobExecution, context: JobContext, error: Error) => Promise<void> | void;
|
|
9
|
+
onJobDeadLetter?: (job: JobExecution, context: JobContext, error: Error) => Promise<void> | void;
|
|
10
|
+
}
|
|
11
|
+
export interface WorkerConfig {
|
|
12
|
+
module: ModuleConfig;
|
|
13
|
+
hooks?: WorkerHooks;
|
|
14
|
+
logger?: Logger;
|
|
15
|
+
}
|
|
16
|
+
export interface JobExecution {
|
|
17
|
+
jobId: string;
|
|
18
|
+
jobName: string;
|
|
19
|
+
payload: unknown;
|
|
20
|
+
attemptNumber: number;
|
|
21
|
+
enqueuedAt: Date;
|
|
22
|
+
metadata?: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Bootstrap a worker Lambda handler for processing jobs.
|
|
26
|
+
*/
|
|
27
|
+
export declare function bootstrapWorker(config: WorkerConfig): (event: SQSEvent | EventBridgeEvent<string, unknown> | Record<string, unknown>, ctx?: Context) => Promise<{
|
|
28
|
+
batchItemFailures: import("aws-lambda").SQSBatchItemFailure[];
|
|
29
|
+
success?: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
success: boolean;
|
|
32
|
+
batchItemFailures?: undefined;
|
|
33
|
+
}>;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/jobs/worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAoB,QAAQ,EAAa,MAAM,YAAY,CAAC;AAGnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAQ/D,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAmB1D,UAAU,WAAW;IACnB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9E,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjF,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7F,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAClG;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AASD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,IAKhD,OAAO,QAAQ,GAAG,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7E,MAAM,OAAO;;;;;;GA8ChB"}
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { asValue, createContainer, InjectionMode } from 'awilix';
|
|
2
|
+
import { object, optional, record, safeParse, string, unknown } from 'valibot';
|
|
3
|
+
import { collectModules, registerModuleProviders, validateNoCycles } from '../core/bootstrap.js';
|
|
4
|
+
import { createLogger } from '../utils/logger.js';
|
|
5
|
+
import { InvalidJobPayloadError, PermanentJobError, RetryExhaustedError, TransientJobError, } from './errors.js';
|
|
6
|
+
import { createJobRegistry } from './job-registry.js';
|
|
7
|
+
import { generateJobId } from './utils.js';
|
|
8
|
+
/**
|
|
9
|
+
* Default maximum retry attempts before a job is considered dead.
|
|
10
|
+
*/
|
|
11
|
+
const DEFAULT_MAX_ATTEMPTS = 25;
|
|
12
|
+
/**
|
|
13
|
+
* Valibot schema for validating SQS job message structure.
|
|
14
|
+
*/
|
|
15
|
+
const JobMessageSchema = object({
|
|
16
|
+
jobName: string(),
|
|
17
|
+
payload: optional(unknown()),
|
|
18
|
+
jobId: optional(string()),
|
|
19
|
+
enqueuedAt: optional(string()),
|
|
20
|
+
metadata: optional(record(string(), string())),
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Bootstrap a worker Lambda handler for processing jobs.
|
|
24
|
+
*/
|
|
25
|
+
export function bootstrapWorker(config) {
|
|
26
|
+
const logger = config.logger ?? createLogger('JobsWorker');
|
|
27
|
+
const statePromise = buildWorkerState(config.module, logger);
|
|
28
|
+
return async (event, ctx) => {
|
|
29
|
+
const { container, registry } = await statePromise;
|
|
30
|
+
if (isSQSEvent(event)) {
|
|
31
|
+
const batchItemFailures = [];
|
|
32
|
+
for (const record of event.Records) {
|
|
33
|
+
try {
|
|
34
|
+
await processRecord(record, {
|
|
35
|
+
registry,
|
|
36
|
+
moduleContainer: container,
|
|
37
|
+
hooks: config.hooks,
|
|
38
|
+
logger,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (_error) {
|
|
42
|
+
batchItemFailures.push({ itemIdentifier: record.messageId });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { batchItemFailures };
|
|
46
|
+
}
|
|
47
|
+
// Non-SQS invocation (e.g., EventBridge periodic jobs)
|
|
48
|
+
const jobName = extractJobName(event);
|
|
49
|
+
const payload = extractPayload(event);
|
|
50
|
+
if (!jobName) {
|
|
51
|
+
throw new Error('Job name is required for non-SQS invocation');
|
|
52
|
+
}
|
|
53
|
+
// Extract attempt number from Lambda context retry metadata if available
|
|
54
|
+
const attemptNumber = extractAttemptNumber(ctx);
|
|
55
|
+
await executeJob({
|
|
56
|
+
jobName,
|
|
57
|
+
jobId: `eb-${generateJobId()}`,
|
|
58
|
+
payload,
|
|
59
|
+
attemptNumber,
|
|
60
|
+
enqueuedAt: new Date(),
|
|
61
|
+
}, { registry, moduleContainer: container, hooks: config.hooks, logger });
|
|
62
|
+
return { success: true };
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async function resolveAsyncFactories(container, names, logger) {
|
|
66
|
+
const resolutions = names.map(async (name) => {
|
|
67
|
+
const resolved = container.resolve(name);
|
|
68
|
+
const value = resolved instanceof Promise ? await resolved : resolved;
|
|
69
|
+
container.register({ [name]: asValue(value) });
|
|
70
|
+
});
|
|
71
|
+
await Promise.all(resolutions).catch((error) => {
|
|
72
|
+
logger.error('Failed to resolve async providers', { error });
|
|
73
|
+
throw error;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async function buildWorkerState(module, logger) {
|
|
77
|
+
const container = createContainer({
|
|
78
|
+
injectionMode: InjectionMode.PROXY,
|
|
79
|
+
strict: true,
|
|
80
|
+
});
|
|
81
|
+
const allModules = collectModules(module);
|
|
82
|
+
validateNoCycles(allModules);
|
|
83
|
+
// Register providers
|
|
84
|
+
const asyncFactories = [];
|
|
85
|
+
for (const mod of allModules) {
|
|
86
|
+
const names = registerModuleProviders(mod, container, logger);
|
|
87
|
+
asyncFactories.push(...names);
|
|
88
|
+
}
|
|
89
|
+
// Resolve async factories before processing jobs
|
|
90
|
+
if (asyncFactories.length > 0) {
|
|
91
|
+
await resolveAsyncFactories(container, asyncFactories, logger);
|
|
92
|
+
}
|
|
93
|
+
const registry = buildJobRegistry(allModules);
|
|
94
|
+
return { container, registry };
|
|
95
|
+
}
|
|
96
|
+
function buildJobRegistry(modules) {
|
|
97
|
+
const registry = createJobRegistry();
|
|
98
|
+
for (const mod of modules) {
|
|
99
|
+
if (mod.jobs) {
|
|
100
|
+
for (const job of mod.jobs) {
|
|
101
|
+
registry.register(job);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return registry;
|
|
106
|
+
}
|
|
107
|
+
async function processRecord(record, context) {
|
|
108
|
+
let parsed;
|
|
109
|
+
try {
|
|
110
|
+
parsed = JSON.parse(record.body);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
context.logger.error('Failed to parse job message body', {
|
|
114
|
+
error,
|
|
115
|
+
messageId: record.messageId,
|
|
116
|
+
});
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
120
|
+
throw new Error('Invalid job message payload');
|
|
121
|
+
}
|
|
122
|
+
// Validate message structure using Valibot
|
|
123
|
+
const validationResult = safeParse(JobMessageSchema, parsed);
|
|
124
|
+
if (!validationResult.success) {
|
|
125
|
+
context.logger.error('Invalid job message structure', {
|
|
126
|
+
messageId: record.messageId,
|
|
127
|
+
issues: validationResult.issues,
|
|
128
|
+
});
|
|
129
|
+
throw new Error('Invalid job message structure');
|
|
130
|
+
}
|
|
131
|
+
const parsedMessage = parsed;
|
|
132
|
+
const jobName = parsedMessage.jobName;
|
|
133
|
+
const payload = parsedMessage.payload;
|
|
134
|
+
const jobId = parsedMessage.jobId ?? record.messageId;
|
|
135
|
+
const enqueuedAt = parsedMessage.enqueuedAt ? new Date(parsedMessage.enqueuedAt) : new Date();
|
|
136
|
+
const metadata = parsedMessage.metadata;
|
|
137
|
+
const attemptNumber = record.attributes?.ApproximateReceiveCount
|
|
138
|
+
? Number.parseInt(record.attributes.ApproximateReceiveCount, 10) || 1
|
|
139
|
+
: 1;
|
|
140
|
+
const execution = {
|
|
141
|
+
jobId,
|
|
142
|
+
jobName,
|
|
143
|
+
payload,
|
|
144
|
+
attemptNumber,
|
|
145
|
+
enqueuedAt,
|
|
146
|
+
metadata,
|
|
147
|
+
};
|
|
148
|
+
await executeJob(execution, context);
|
|
149
|
+
}
|
|
150
|
+
async function executeJob(execution, context) {
|
|
151
|
+
const job = context.registry.getOrThrow(execution.jobName);
|
|
152
|
+
// Normalize retry configuration
|
|
153
|
+
const retryConfig = normalizeRetryConfig(job.retry);
|
|
154
|
+
const scope = context.moduleContainer.createScope();
|
|
155
|
+
const services = scope.cradle;
|
|
156
|
+
const jobLogger = resolveJobLogger(context, execution);
|
|
157
|
+
const jobContext = {
|
|
158
|
+
services,
|
|
159
|
+
jobId: execution.jobId,
|
|
160
|
+
attemptNumber: execution.attemptNumber,
|
|
161
|
+
enqueuedAt: execution.enqueuedAt,
|
|
162
|
+
logger: jobLogger,
|
|
163
|
+
};
|
|
164
|
+
try {
|
|
165
|
+
await context.hooks?.onJobStart?.(execution, jobContext);
|
|
166
|
+
if (job.schema) {
|
|
167
|
+
const result = safeParse(job.schema, execution.payload);
|
|
168
|
+
if (!result.success) {
|
|
169
|
+
throw new InvalidJobPayloadError(job.name, result.issues);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
await job.handler(execution.payload, jobContext);
|
|
173
|
+
await context.hooks?.onJobComplete?.(execution, jobContext);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
await handleJobError(error, execution, jobContext, context, retryConfig, jobLogger);
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
await scope.dispose();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Resolve the logger for job execution, scoped to the job if possible.
|
|
184
|
+
*/
|
|
185
|
+
function resolveJobLogger(context, execution) {
|
|
186
|
+
if (!context.moduleContainer.hasRegistration('logger')) {
|
|
187
|
+
return context.logger;
|
|
188
|
+
}
|
|
189
|
+
const baseLogger = context.moduleContainer.resolve('logger');
|
|
190
|
+
return baseLogger?.child
|
|
191
|
+
? baseLogger.child({ jobId: execution.jobId, jobName: execution.jobName })
|
|
192
|
+
: baseLogger;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Handle job execution errors with retry logic.
|
|
196
|
+
*/
|
|
197
|
+
async function handleJobError(err, execution, jobContext, context, retryConfig, jobLogger) {
|
|
198
|
+
const { maxAttempts, dead: sendToDead } = retryConfig;
|
|
199
|
+
// PermanentJobError: Never retry, go straight to DLQ
|
|
200
|
+
if (err instanceof PermanentJobError) {
|
|
201
|
+
jobLogger?.error('Job permanently failed', { err });
|
|
202
|
+
await context.hooks?.onJobFailed?.(execution, jobContext, err);
|
|
203
|
+
await context.hooks?.onJobDeadLetter?.(execution, jobContext, err);
|
|
204
|
+
throw err;
|
|
205
|
+
}
|
|
206
|
+
// No retries configured: discard the job silently
|
|
207
|
+
if (maxAttempts === false) {
|
|
208
|
+
jobLogger?.warn('Job failed with retries disabled, discarding', {
|
|
209
|
+
err,
|
|
210
|
+
jobName: execution.jobName,
|
|
211
|
+
jobId: execution.jobId,
|
|
212
|
+
});
|
|
213
|
+
await context.hooks?.onJobFailed?.(execution, jobContext, err);
|
|
214
|
+
// Return without throwing to acknowledge and discard the message
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
// Check if retries are exhausted
|
|
218
|
+
if (execution.attemptNumber >= maxAttempts) {
|
|
219
|
+
return handleExhaustedRetries(err, execution, jobContext, context, maxAttempts, sendToDead, jobLogger);
|
|
220
|
+
}
|
|
221
|
+
// Normal failure: log and throw to trigger SQS retry
|
|
222
|
+
await context.hooks?.onJobFailed?.(execution, jobContext, err);
|
|
223
|
+
logRetryableError(err, execution, maxAttempts, jobLogger);
|
|
224
|
+
throw err;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Handle the case when all retries are exhausted.
|
|
228
|
+
*/
|
|
229
|
+
async function handleExhaustedRetries(err, execution, jobContext, context, maxAttempts, sendToDead, jobLogger) {
|
|
230
|
+
const exhaustedError = new RetryExhaustedError(execution.jobName, execution.attemptNumber, maxAttempts, err);
|
|
231
|
+
jobLogger?.error('Job retries exhausted', {
|
|
232
|
+
err,
|
|
233
|
+
attemptNumber: execution.attemptNumber,
|
|
234
|
+
maxAttempts,
|
|
235
|
+
cause: err.message,
|
|
236
|
+
});
|
|
237
|
+
await context.hooks?.onJobFailed?.(execution, jobContext, err);
|
|
238
|
+
await context.hooks?.onJobDeadLetter?.(execution, jobContext, exhaustedError);
|
|
239
|
+
if (!sendToDead) {
|
|
240
|
+
jobLogger?.info('Job discarded (dead: false)', {
|
|
241
|
+
jobName: execution.jobName,
|
|
242
|
+
jobId: execution.jobId,
|
|
243
|
+
});
|
|
244
|
+
// Return without throwing to discard
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
throw exhaustedError;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Log a retriable error with appropriate context.
|
|
251
|
+
*/
|
|
252
|
+
function logRetryableError(err, execution, maxAttempts, jobLogger) {
|
|
253
|
+
if (err instanceof InvalidJobPayloadError) {
|
|
254
|
+
jobLogger?.warn('Invalid job payload, retrying until DLQ', {
|
|
255
|
+
err,
|
|
256
|
+
jobName: execution.jobName,
|
|
257
|
+
jobId: execution.jobId,
|
|
258
|
+
attemptNumber: execution.attemptNumber,
|
|
259
|
+
maxAttempts,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
else if (err instanceof TransientJobError) {
|
|
263
|
+
jobLogger?.warn('Job transient failure, retrying', {
|
|
264
|
+
err,
|
|
265
|
+
retryAfter: err.retryAfter,
|
|
266
|
+
attemptNumber: execution.attemptNumber,
|
|
267
|
+
maxAttempts,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
jobLogger?.warn('Job failed, will retry', {
|
|
272
|
+
err,
|
|
273
|
+
attemptNumber: execution.attemptNumber,
|
|
274
|
+
maxAttempts,
|
|
275
|
+
remainingAttempts: maxAttempts - execution.attemptNumber,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Normalize retry configuration to a consistent format.
|
|
281
|
+
* Zero or negative maxAttempts are treated as "no retries" (same as retry: false).
|
|
282
|
+
*/
|
|
283
|
+
function normalizeRetryConfig(config) {
|
|
284
|
+
if (config === false) {
|
|
285
|
+
return { maxAttempts: false, dead: false };
|
|
286
|
+
}
|
|
287
|
+
if (typeof config === 'number') {
|
|
288
|
+
// Treat zero or negative as "no retries"
|
|
289
|
+
if (config <= 0) {
|
|
290
|
+
return { maxAttempts: false, dead: false };
|
|
291
|
+
}
|
|
292
|
+
return { maxAttempts: config, dead: true };
|
|
293
|
+
}
|
|
294
|
+
if (config === undefined) {
|
|
295
|
+
return { maxAttempts: DEFAULT_MAX_ATTEMPTS, dead: true };
|
|
296
|
+
}
|
|
297
|
+
// Handle object config with potential invalid maxAttempts
|
|
298
|
+
const maxAttempts = config.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
299
|
+
if (maxAttempts <= 0) {
|
|
300
|
+
return { maxAttempts: false, dead: false };
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
maxAttempts,
|
|
304
|
+
dead: config.dead ?? true,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Type guard to check if an event is an SQS event.
|
|
309
|
+
* Validates presence of Records array with SQS-specific properties.
|
|
310
|
+
*/
|
|
311
|
+
function isSQSEvent(event) {
|
|
312
|
+
const maybeEvent = event;
|
|
313
|
+
if (!Array.isArray(maybeEvent?.Records) || maybeEvent.Records.length === 0) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
const firstRecord = maybeEvent.Records[0];
|
|
317
|
+
// Check for SQS-specific properties to distinguish from other AWS event types
|
|
318
|
+
return (typeof firstRecord.messageId === 'string' &&
|
|
319
|
+
typeof firstRecord.body === 'string' &&
|
|
320
|
+
typeof firstRecord.receiptHandle === 'string');
|
|
321
|
+
}
|
|
322
|
+
function extractJobName(event) {
|
|
323
|
+
if (typeof event.jobName === 'string')
|
|
324
|
+
return event.jobName;
|
|
325
|
+
const detail = event.detail;
|
|
326
|
+
if (detail && typeof detail.jobName === 'string')
|
|
327
|
+
return detail.jobName;
|
|
328
|
+
if (detail && typeof detail.name === 'string')
|
|
329
|
+
return detail.name;
|
|
330
|
+
return undefined;
|
|
331
|
+
}
|
|
332
|
+
function extractPayload(event) {
|
|
333
|
+
if ('payload' in event)
|
|
334
|
+
return event.payload;
|
|
335
|
+
const detail = event.detail;
|
|
336
|
+
if (detail && 'payload' in detail)
|
|
337
|
+
return detail.payload;
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Extract attempt number from Lambda context.
|
|
342
|
+
* For EventBridge retries, checks for retry metadata in the context.
|
|
343
|
+
*/
|
|
344
|
+
function extractAttemptNumber(ctx) {
|
|
345
|
+
if (!ctx)
|
|
346
|
+
return 1;
|
|
347
|
+
// EventBridge retry information may be available in client context
|
|
348
|
+
// or through environment variables in some configurations
|
|
349
|
+
try {
|
|
350
|
+
const clientContext = ctx
|
|
351
|
+
.clientContext;
|
|
352
|
+
if (clientContext?.custom?.retryAttempt !== undefined) {
|
|
353
|
+
return clientContext.custom.retryAttempt + 1;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
// Ignore parsing errors
|
|
358
|
+
}
|
|
359
|
+
return 1;
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/jobs/worker.ts"],"names":[],"mappings":"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"}
|