ravenflow 0.3.0 → 0.4.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/README.md +124 -266
- package/dist/index.d.mts +315 -625
- package/dist/index.d.ts +315 -625
- package/dist/index.js +2781 -2644
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2789 -2607
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -11
- package/LICENSE +0 -21
package/dist/index.d.ts
CHANGED
|
@@ -1,673 +1,363 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Job, Queue, QueueEvents, ConnectionOptions, Worker, WorkerOptions } from 'bullmq';
|
|
1
|
+
import { Job, ConnectionOptions, Queue } from 'bullmq';
|
|
3
2
|
import pino from 'pino';
|
|
4
|
-
import {
|
|
3
|
+
import { Db } from 'mongodb';
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
delay: number;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
declare const zRateLimitConfig: z.ZodUnion<readonly [z.ZodObject<{
|
|
16
|
-
perSecond: z.ZodNumber;
|
|
17
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
18
|
-
perMinute: z.ZodNumber;
|
|
19
|
-
}, z.core.$strip>]>;
|
|
20
|
-
type RateLimitConfig = z.infer<typeof zRateLimitConfig>;
|
|
21
|
-
interface MemoryEtlStepConfig {
|
|
22
|
-
rateLimit?: RateLimitConfig;
|
|
23
|
-
}
|
|
24
|
-
interface StepConfig extends MemoryEtlStepConfig {
|
|
25
|
-
attempts?: number;
|
|
26
|
-
backoff?: {
|
|
27
|
-
type: "fixed" | "exponential";
|
|
28
|
-
delay: number;
|
|
29
|
-
};
|
|
30
|
-
queue?: string;
|
|
5
|
+
declare const CONTINUATION: unique symbol;
|
|
6
|
+
interface Continuation<TPayload> {
|
|
7
|
+
readonly [CONTINUATION]: true;
|
|
8
|
+
readonly params: TPayload;
|
|
9
|
+
readonly delayMs?: number;
|
|
10
|
+
readonly deduplicationId?: string;
|
|
31
11
|
}
|
|
32
|
-
interface
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
hasMore: boolean;
|
|
36
|
-
}
|
|
37
|
-
declare const zJobStatus: z.ZodEnum<{
|
|
38
|
-
pending: "pending";
|
|
39
|
-
in_progress: "in_progress";
|
|
40
|
-
completed: "completed";
|
|
41
|
-
failed: "failed";
|
|
42
|
-
stalled: "stalled";
|
|
43
|
-
}>;
|
|
44
|
-
type JobStatus = z.infer<typeof zJobStatus>;
|
|
45
|
-
|
|
46
|
-
interface SimpleJobConfig<TData, TReturn> extends BaseJobConfig {
|
|
47
|
-
type: "simple";
|
|
48
|
-
handler: (job: Job, params: TData) => Promise<TReturn>;
|
|
12
|
+
interface ContinueOptions {
|
|
13
|
+
delayMs?: number;
|
|
14
|
+
deduplicationId?: string;
|
|
49
15
|
}
|
|
50
|
-
declare function defineSimpleJob<TData, TReturn>(config: Omit<SimpleJobConfig<TData, TReturn>, "type">): SimpleJobConfig<TData, TReturn>;
|
|
51
16
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
steps?: {
|
|
58
|
-
extract?: MemoryEtlStepConfig;
|
|
59
|
-
transform?: MemoryEtlStepConfig;
|
|
60
|
-
load?: MemoryEtlStepConfig;
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
declare function defineMemoryEtlJob<TRaw, TProcessed, TCursor = number>(config: Omit<MemoryEtlJobConfig<TRaw, TProcessed, TCursor>, "type">): MemoryEtlJobConfig<TRaw, TProcessed, TCursor>;
|
|
17
|
+
type Logger = pino.Logger;
|
|
18
|
+
interface LoggerOptions {
|
|
19
|
+
level?: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
20
|
+
pretty?: boolean;
|
|
21
|
+
}
|
|
64
22
|
|
|
65
|
-
interface
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
load?: StepConfig;
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
declare function defineDistributedEtlJob<TRaw, TProcessed, TCursor = number>(config: Omit<DistributedEtlJobConfig<TRaw, TProcessed, TCursor>, "type">): DistributedEtlJobConfig<TRaw, TProcessed, TCursor>;
|
|
23
|
+
interface JobContext<TParams> {
|
|
24
|
+
params: TParams;
|
|
25
|
+
deduplicationId?: string;
|
|
26
|
+
continueWith(params: TParams, options?: ContinueOptions): Continuation<TParams>;
|
|
27
|
+
job: Job;
|
|
28
|
+
logger: Logger;
|
|
29
|
+
signal: AbortSignal;
|
|
30
|
+
}
|
|
77
31
|
|
|
78
|
-
interface
|
|
79
|
-
type: "
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
declare function defineStatefulEtlJob<TRaw, TProcessed, TCursor = string>(config: Omit<StatefulEtlJobConfig<TRaw, TProcessed, TCursor>, "type">): StatefulEtlJobConfig<TRaw, TProcessed, TCursor>;
|
|
32
|
+
interface BackoffPolicy {
|
|
33
|
+
type: "fixed" | "exponential";
|
|
34
|
+
delayMs: number;
|
|
35
|
+
jitter?: number;
|
|
36
|
+
}
|
|
37
|
+
type DeduplicatePolicy<TPayload> = true | ((params: TPayload) => string);
|
|
38
|
+
type PacePolicy = {
|
|
39
|
+
perSecond: number;
|
|
40
|
+
perMinute?: never;
|
|
41
|
+
perHour?: never;
|
|
42
|
+
} | {
|
|
43
|
+
perMinute: number;
|
|
44
|
+
perSecond?: never;
|
|
45
|
+
perHour?: never;
|
|
46
|
+
} | {
|
|
47
|
+
perHour: number;
|
|
48
|
+
perSecond?: never;
|
|
49
|
+
perMinute?: never;
|
|
50
|
+
};
|
|
98
51
|
|
|
99
|
-
type
|
|
100
|
-
interface
|
|
101
|
-
type: "token-bucket";
|
|
52
|
+
type JobTrigger = CronTrigger | SpoolTriggerDeclaration;
|
|
53
|
+
interface CronTrigger {
|
|
102
54
|
cron: string;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
55
|
+
spool?: never;
|
|
56
|
+
}
|
|
57
|
+
interface SpoolTriggerDeclaration {
|
|
58
|
+
spool: SpoolTrigger;
|
|
59
|
+
cron?: never;
|
|
60
|
+
}
|
|
61
|
+
interface SpoolTrigger {
|
|
62
|
+
name: string;
|
|
63
|
+
tickMs?: number;
|
|
64
|
+
canPull?: () => boolean | Promise<boolean>;
|
|
65
|
+
expireUnclaimedAfterMs?: number;
|
|
66
|
+
}
|
|
67
|
+
interface DeclaredTrigger {
|
|
68
|
+
cron?: string;
|
|
69
|
+
spool?: SpoolTrigger;
|
|
70
|
+
}
|
|
113
71
|
|
|
114
|
-
type
|
|
72
|
+
type TriggerFor<TPayload> = SatisfiableByNothing<TPayload> extends true ? JobTrigger : SpoolTriggerDeclaration | CronRefused;
|
|
73
|
+
type CronTriggerFor<TPayload> = SatisfiableByNothing<TPayload> extends true ? CronTrigger : CronRefused;
|
|
74
|
+
type SatisfiableByNothing<TPayload> = AcceptsUndefined<TPayload> extends true ? true : AcceptsEmptyObject<TPayload>;
|
|
75
|
+
type AcceptsUndefined<TPayload> = undefined extends TPayload ? true : false;
|
|
76
|
+
type AcceptsEmptyObject<TPayload> = {} extends TPayload ? true : false;
|
|
77
|
+
interface CronRefused {
|
|
78
|
+
cron?: CronNeedsAPayloadNothingHasToProvide;
|
|
79
|
+
spool?: never;
|
|
80
|
+
}
|
|
81
|
+
type CronNeedsAPayloadNothingHasToProvide = "a cron trigger has nothing to pass this job: make every field of its payload optional, or declare the payload as void";
|
|
115
82
|
|
|
116
|
-
interface
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
83
|
+
interface JobDefinition<TPayload, TResult> {
|
|
84
|
+
queue?: string;
|
|
85
|
+
attempts?: number;
|
|
86
|
+
backoff?: BackoffPolicy;
|
|
87
|
+
trigger?: TriggerFor<TPayload>;
|
|
88
|
+
deduplicate?: DeduplicatePolicy<TPayload>;
|
|
89
|
+
pace?: PacePolicy;
|
|
90
|
+
handler: JobHandler<TPayload, TResult>;
|
|
91
|
+
}
|
|
92
|
+
type JobHandler<TPayload, TResult> = (ctx: JobContext<TPayload>) => Promise<TResult | Continuation<TPayload>>;
|
|
93
|
+
type SpoolFedJob<TPayload, TResult> = JobDefinition<TPayload, TResult> & {
|
|
94
|
+
trigger: SpoolTriggerDeclaration;
|
|
95
|
+
pace: PacePolicy;
|
|
96
|
+
};
|
|
97
|
+
type ClockFedJob<TPayload, TResult> = JobDefinition<TPayload, TResult> & {
|
|
98
|
+
trigger: CronTrigger;
|
|
99
|
+
};
|
|
100
|
+
declare function defineJob<TPayload, TResult>(definition: JobDefinitionWith<SpoolTriggerDeclaration, TPayload, TResult> & {
|
|
101
|
+
pace: PacePolicy;
|
|
102
|
+
}): SpoolFedJob<TPayload, TResult>;
|
|
103
|
+
declare function defineJob<TPayload, TResult>(definition: JobDefinitionWith<CronTriggerFor<TPayload>, TPayload, TResult>): ClockFedJob<TPayload, TResult>;
|
|
104
|
+
declare function defineJob<TPayload, TResult>(definition: UnspooledJobDefinition<TPayload, TResult>): JobDefinition<TPayload, TResult>;
|
|
105
|
+
type JobDefinitionWith<TTrigger, TPayload, TResult> = Omit<JobDefinition<TPayload, TResult>, "trigger"> & {
|
|
106
|
+
trigger: TTrigger;
|
|
107
|
+
};
|
|
108
|
+
type UnspooledJobDefinition<TPayload, TResult> = Omit<JobDefinition<TPayload, TResult>, "trigger"> & {
|
|
109
|
+
trigger?: CronTriggerFor<TPayload>;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
interface AnyJob {
|
|
113
|
+
queue?: string;
|
|
114
|
+
attempts?: number;
|
|
115
|
+
backoff?: BackoffPolicy;
|
|
116
|
+
trigger?: DeclaredTrigger;
|
|
117
|
+
deduplicate?: DeduplicatePolicy<never>;
|
|
118
|
+
pace?: PacePolicy;
|
|
119
|
+
handler: (ctx: JobContext<never>) => Promise<unknown>;
|
|
121
120
|
}
|
|
121
|
+
|
|
122
122
|
interface RavenflowConfig<TJobs extends string = string> {
|
|
123
123
|
defaultQueue: string;
|
|
124
|
-
jobs: Record<TJobs,
|
|
124
|
+
jobs: Record<TJobs, AnyJob>;
|
|
125
|
+
logger?: LoggerOptions;
|
|
126
|
+
queuesRetention?: QueuesRetentionConfig;
|
|
127
|
+
jobResultsRetentionHours?: number;
|
|
128
|
+
aggregatedResultsRetentionHours?: number;
|
|
129
|
+
}
|
|
130
|
+
interface QueuesRetentionConfig {
|
|
131
|
+
completedCount?: number;
|
|
132
|
+
failedCount?: number;
|
|
125
133
|
}
|
|
126
|
-
type JobNames<T extends RavenflowConfig> = T extends RavenflowConfig<infer TJobs> ? TJobs : never;
|
|
127
134
|
declare function defineConfig<const T extends RavenflowConfig>(config: T): T;
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
sendAndWait: () => Promise<EtlResult>;
|
|
140
|
-
} : T extends DistributedEtlJobConfig<any, any> ? {
|
|
141
|
-
send: () => Promise<void>;
|
|
142
|
-
sendAndWait: () => Promise<EtlResult>;
|
|
143
|
-
} : T extends StatefulEtlJobConfig<any, any, any> ? {
|
|
144
|
-
send: () => Promise<void>;
|
|
145
|
-
sendAndWait: () => Promise<void>;
|
|
146
|
-
} : T extends TokenBucketJobConfig ? {
|
|
147
|
-
send: () => Promise<void>;
|
|
148
|
-
sendAndWait: () => Promise<void>;
|
|
149
|
-
} : never;
|
|
150
|
-
type JobsProxy<TJobs extends Record<string, JobConfig>> = {
|
|
151
|
-
[K in keyof TJobs]: JobProxy<TJobs[K]>;
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
type Logger = pino.Logger;
|
|
155
|
-
interface LoggerOptions {
|
|
156
|
-
level?: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
157
|
-
pretty?: boolean;
|
|
136
|
+
declare class MongoConnection {
|
|
137
|
+
private readonly uri;
|
|
138
|
+
private client;
|
|
139
|
+
private database;
|
|
140
|
+
private connecting;
|
|
141
|
+
constructor(uri: string);
|
|
142
|
+
connect(): Promise<Db>;
|
|
143
|
+
close(): Promise<void>;
|
|
144
|
+
private openTheDatabase;
|
|
145
|
+
private forgetTheAttempt;
|
|
158
146
|
}
|
|
159
|
-
declare function initLogger(options?: LoggerOptions): Logger;
|
|
160
|
-
declare function getLogger(): Logger;
|
|
161
147
|
|
|
162
|
-
type
|
|
163
|
-
queue: Queue;
|
|
164
|
-
events: QueueEvents;
|
|
165
|
-
}>;
|
|
148
|
+
type ControlKey = `job:${string}`;
|
|
166
149
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
150
|
+
interface ControlPublisher {
|
|
151
|
+
publish(key: ControlKey): Promise<void>;
|
|
152
|
+
}
|
|
153
|
+
declare class ControlChannel implements ControlPublisher {
|
|
154
|
+
private readonly connection;
|
|
155
|
+
private readonly logger;
|
|
156
|
+
private publisher;
|
|
157
|
+
private subscriber;
|
|
158
|
+
constructor(connection: ConnectionOptions, logger: Logger);
|
|
159
|
+
publish(key: ControlKey): Promise<void>;
|
|
160
|
+
subscribe(onInvalidate: (key: ControlKey) => void): Promise<void>;
|
|
161
|
+
close(): Promise<void>;
|
|
162
|
+
private deliver;
|
|
163
|
+
private listenOn;
|
|
164
|
+
private open;
|
|
178
165
|
}
|
|
179
166
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
success: boolean;
|
|
187
|
-
durationMs?: number;
|
|
188
|
-
}
|
|
189
|
-
interface JobStatsDoc {
|
|
190
|
-
jobType: string;
|
|
191
|
-
bucketStart: Date;
|
|
192
|
-
granularity: BucketGranularity;
|
|
193
|
-
count: number;
|
|
194
|
-
success: number;
|
|
195
|
-
failed: number;
|
|
196
|
-
totalDurationMs: number;
|
|
197
|
-
createdAt: Date;
|
|
198
|
-
updatedAt: Date;
|
|
199
|
-
}
|
|
200
|
-
interface JobErrorDoc {
|
|
201
|
-
signature: string;
|
|
202
|
-
jobType: string;
|
|
203
|
-
message: string;
|
|
204
|
-
stack: string;
|
|
205
|
-
count: number;
|
|
206
|
-
firstSeenAt: Date;
|
|
207
|
-
lastSeenAt: Date;
|
|
208
|
-
createdAt: Date;
|
|
209
|
-
updatedAt: Date;
|
|
210
|
-
/** Normalized `Error.cause` chain beyond the top-level error. OMITTED when empty. */
|
|
211
|
-
causeChain?: Array<{
|
|
212
|
-
message: string;
|
|
213
|
-
name: string;
|
|
214
|
-
}>;
|
|
215
|
-
}
|
|
216
|
-
interface RecordOccurrenceInput {
|
|
217
|
-
jobType: string;
|
|
218
|
-
error: unknown;
|
|
219
|
-
}
|
|
220
|
-
interface TopErrorsOptions {
|
|
221
|
-
limit: number;
|
|
222
|
-
jobType?: string;
|
|
223
|
-
/**
|
|
224
|
-
* When set, restricts results to errors whose `lastSeenAt >= since`.
|
|
225
|
-
* Dashboard health views pass the range start (e.g. 7 days ago, UTC midnight)
|
|
226
|
-
* so "top errors" matches the displayed range; omitting returns all errors
|
|
227
|
-
* back to the collection's 90-day TTL boundary.
|
|
228
|
-
*/
|
|
229
|
-
since?: Date;
|
|
230
|
-
}
|
|
231
|
-
interface JobFailureDoc {
|
|
232
|
-
jobId: string;
|
|
233
|
-
jobType: string;
|
|
234
|
-
input: string;
|
|
235
|
-
errorMessage: string;
|
|
236
|
-
errorStack: string;
|
|
237
|
-
logs: string;
|
|
238
|
-
failedAt: Date;
|
|
239
|
-
createdAt: Date;
|
|
240
|
-
/** Normalized `Error.cause` chain beyond the top-level error. OMITTED when empty. */
|
|
241
|
-
causeChain?: Array<{
|
|
242
|
-
message: string;
|
|
243
|
-
name: string;
|
|
244
|
-
}>;
|
|
245
|
-
}
|
|
246
|
-
interface RecordFailureInput {
|
|
247
|
-
jobId: string;
|
|
248
|
-
jobType: string;
|
|
249
|
-
input: unknown;
|
|
250
|
-
error: unknown;
|
|
251
|
-
failedAt: Date;
|
|
252
|
-
logs?: string;
|
|
253
|
-
}
|
|
254
|
-
interface ListFailuresOptions {
|
|
255
|
-
jobType?: string;
|
|
256
|
-
fromDate?: Date | null;
|
|
257
|
-
toDate?: Date | null;
|
|
258
|
-
skip?: number;
|
|
259
|
-
limit?: number;
|
|
260
|
-
}
|
|
261
|
-
declare const JOB_FAILURES_INPUT_MAX_CHARS = 100000;
|
|
262
|
-
declare const JOB_FAILURES_MESSAGE_MAX_CHARS = 2000;
|
|
263
|
-
declare const JOB_FAILURES_STACK_MAX_CHARS = 8000;
|
|
264
|
-
declare const JOB_FAILURES_LOGS_MAX_CHARS = 500000;
|
|
265
|
-
interface WorkerQueueEntry {
|
|
266
|
-
name: string;
|
|
267
|
-
concurrency: number;
|
|
268
|
-
}
|
|
269
|
-
interface WorkerDoc {
|
|
270
|
-
workerId: string;
|
|
271
|
-
hostname: string;
|
|
272
|
-
pid: number;
|
|
273
|
-
queues: WorkerQueueEntry[];
|
|
274
|
-
startedAt: Date;
|
|
275
|
-
lastHeartbeatAt: Date;
|
|
276
|
-
createdAt: Date;
|
|
277
|
-
updatedAt: Date;
|
|
167
|
+
declare const LEVERS: readonly ["executionPaused", "triggerPaused", "ingestPaused"];
|
|
168
|
+
type Lever = (typeof LEVERS)[number];
|
|
169
|
+
type JobControls = Record<Lever, boolean>;
|
|
170
|
+
|
|
171
|
+
interface ControlReads {
|
|
172
|
+
read(jobName: string): Promise<JobControls>;
|
|
278
173
|
}
|
|
279
|
-
interface
|
|
280
|
-
|
|
281
|
-
hostname: string;
|
|
282
|
-
pid: number;
|
|
283
|
-
queues: WorkerQueueEntry[];
|
|
284
|
-
startedAt: Date;
|
|
285
|
-
}
|
|
286
|
-
interface UpsertWorkerQueueInput {
|
|
287
|
-
workerId: string;
|
|
288
|
-
queue: WorkerQueueEntry;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Read shape for the `job_configs` collection — what `JobConfigsRepo.getConfig`
|
|
292
|
-
* returns (with persistence timestamps stripped, or synthesized for absent records).
|
|
293
|
-
*
|
|
294
|
-
* Distinct from `JobConfig` (in `src/types/job/unions.ts`), which is the discriminated
|
|
295
|
-
* union of job-definition types (simple / memory-etl / distributed-etl / etc.) used
|
|
296
|
-
* at app-registration time. `JobConfigEntry` is the runtime persistence shape for
|
|
297
|
-
* dashboard-managed per-job-type settings (enabled flag + free-form metadata).
|
|
298
|
-
*/
|
|
299
|
-
interface JobConfigEntry {
|
|
300
|
-
jobType: string;
|
|
301
|
-
enabled: boolean;
|
|
302
|
-
metadata: Record<string, unknown>;
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Persisted shape for the `job_configs` collection — the read shape plus
|
|
306
|
-
* MongoDB-managed timestamps. Returned by `JobConfigsRepo.listAll` (every row
|
|
307
|
-
* there is, by definition, persisted, so the timestamps are always real).
|
|
308
|
-
*/
|
|
309
|
-
interface JobConfigDoc extends JobConfigEntry {
|
|
310
|
-
createdAt: Date;
|
|
311
|
-
updatedAt: Date;
|
|
174
|
+
interface JobControlPlane extends ControlReads {
|
|
175
|
+
write(jobName: string, patch: Partial<JobControls>): Promise<void>;
|
|
312
176
|
}
|
|
313
177
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
178
|
+
interface LeverEntry {
|
|
179
|
+
key: ControlKey;
|
|
180
|
+
lever: Lever;
|
|
181
|
+
value: string;
|
|
182
|
+
}
|
|
183
|
+
interface StoredLever {
|
|
184
|
+
jobName: string;
|
|
185
|
+
lever: Lever;
|
|
186
|
+
value: string;
|
|
187
|
+
}
|
|
188
|
+
declare class ControlHash {
|
|
189
|
+
private readonly options;
|
|
190
|
+
private readonly logger;
|
|
191
|
+
private connection;
|
|
192
|
+
constructor(options: ConnectionOptions, logger: Logger);
|
|
193
|
+
readLevers(key: ControlKey): Promise<Map<Lever, string>>;
|
|
194
|
+
readEveryLever(): Promise<StoredLever[]>;
|
|
195
|
+
write(entry: LeverEntry): Promise<void>;
|
|
196
|
+
writeIfAbsent(entry: LeverEntry): Promise<boolean>;
|
|
197
|
+
close(): Promise<void>;
|
|
198
|
+
private get redis();
|
|
319
199
|
}
|
|
320
200
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
registerWorker(input: RegisterWorkerInput): Promise<void>;
|
|
325
|
-
updateHeartbeat(workerId: string): Promise<void>;
|
|
326
|
-
/**
|
|
327
|
-
* Appends or replaces a queue entry on the worker's record.
|
|
328
|
-
*
|
|
329
|
-
* Single-writer invariant: this method is NOT atomic under concurrent writers to the
|
|
330
|
-
* SAME `workerId`. WorkerRegistry is a process-local singleton, and `workerId` is
|
|
331
|
-
* unique per process by contract (default: `<hostname>:<pid>:<uuid>`). Sharing a
|
|
332
|
-
* stable `workerId` across processes violates AC #6 and will race last-writer-wins.
|
|
333
|
-
*/
|
|
334
|
-
addQueue(input: UpsertWorkerQueueInput): Promise<void>;
|
|
335
|
-
deregisterWorker(workerId: string): Promise<void>;
|
|
336
|
-
findAlive(maxHeartbeatAgeMs: number): Promise<WorkerDoc[]>;
|
|
337
|
-
cleanupStale(maxHeartbeatAgeMs: number): Promise<number>;
|
|
338
|
-
private validateRegisterInput;
|
|
339
|
-
private validateQueueEntry;
|
|
340
|
-
private validateMaxHeartbeatAgeMs;
|
|
201
|
+
interface MirroredControls extends Partial<JobControls> {
|
|
202
|
+
_id: string;
|
|
203
|
+
updatedAt: Date;
|
|
341
204
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
protected indexes(): IndexDescriptor[];
|
|
346
|
-
/**
|
|
347
|
-
* Builds the bulk write operations for a stats increment WITHOUT executing them.
|
|
348
|
-
* Returns TWO ops — one for the hour bucket, one for the day bucket — matching
|
|
349
|
-
* `incrementStats`'s direct-call shape bit-for-bit. Intended to be pushed through
|
|
350
|
-
* a `BatchWriter` by the event-hooks layer (Story 1.7). Throws synchronously on
|
|
351
|
-
* invalid `durationMs`; otherwise no side effects.
|
|
352
|
-
*
|
|
353
|
-
* NOTE: `now` is captured at builder invocation time, NOT at BatchWriter flush
|
|
354
|
-
* time — `createdAt`, `updatedAt`, and `bucketStart` all reflect the event's
|
|
355
|
-
* wall-clock, not the flush wall-clock. Aggregations are therefore correctly
|
|
356
|
-
* attributed to the hour/day the event occurred, even if the batch flush is
|
|
357
|
-
* delayed by the buffer timer.
|
|
358
|
-
*/
|
|
359
|
-
toIncrementStatsOps(jobType: string, input: IncrementStatsInput): AnyBulkWriteOperation<JobStatsDoc>[];
|
|
360
|
-
incrementStats(jobType: string, input: IncrementStatsInput): Promise<void>;
|
|
361
|
-
getStats(jobType: string, fromDate: Date, toDate: Date, granularity: BucketGranularity): Promise<JobStatsDoc[]>;
|
|
362
|
-
/**
|
|
363
|
-
* Fetches every stats document in the given range + granularity, across ALL
|
|
364
|
-
* jobTypes. Intended for dashboard views that need a cross-jobType overview
|
|
365
|
-
* (e.g., "7-day health per job type") without a prior enumeration step.
|
|
366
|
-
*
|
|
367
|
-
* Result order: `bucketStart` ascending, then `jobType` ascending. Caller is
|
|
368
|
-
* responsible for grouping by jobType client-side if desired.
|
|
369
|
-
*
|
|
370
|
-
* Applies the same `MAX_GET_STATS_RESULTS` cap as `getStats` — a single query
|
|
371
|
-
* across all jobTypes × buckets × granularity is bounded, but the cap keeps
|
|
372
|
-
* the method safe under accidental wide-range queries.
|
|
373
|
-
*/
|
|
374
|
-
getStatsAllJobTypes(fromDate: Date, toDate: Date, granularity: BucketGranularity): Promise<JobStatsDoc[]>;
|
|
375
|
-
private upsertBucket;
|
|
376
|
-
private buildBucketOp;
|
|
377
|
-
private buildBucketPayload;
|
|
378
|
-
private validateDurationMs;
|
|
205
|
+
interface ControlMirror {
|
|
206
|
+
mirrorJobControls(jobName: string, patch: Partial<JobControls>): Promise<void>;
|
|
207
|
+
listAll(): Promise<MirroredControls[]>;
|
|
379
208
|
}
|
|
380
209
|
|
|
381
|
-
|
|
382
|
-
constructor(db: Db);
|
|
383
|
-
protected indexes(): IndexDescriptor[];
|
|
384
|
-
/**
|
|
385
|
-
* Records one occurrence of an error, deduplicated by its stable signature.
|
|
386
|
-
*
|
|
387
|
-
* Invariant: `jobType` is set **only on insert** (`$setOnInsert`). Once a signature
|
|
388
|
-
* is first observed under jobType A, subsequent occurrences under jobType B do NOT
|
|
389
|
-
* overwrite the stored value. The signature is the identity of the error; a signature
|
|
390
|
-
* appearing across multiple job types indicates shared infrastructure failure (e.g.
|
|
391
|
-
* ECONNRESET from the shared DB) and is worth surfacing on the first-observed job.
|
|
392
|
-
*/
|
|
393
|
-
recordOccurrence(input: RecordOccurrenceInput): Promise<void>;
|
|
394
|
-
/**
|
|
395
|
-
* Builds the bulk write operation for `recordOccurrence` WITHOUT executing it.
|
|
396
|
-
* Returns a single upsert op matching the direct-call shape bit-for-bit.
|
|
397
|
-
*
|
|
398
|
-
* NOTE: `now` is captured at builder invocation time, NOT at BatchWriter flush
|
|
399
|
-
* time — firstSeenAt / lastSeenAt reflect the event's wall-clock, not the
|
|
400
|
-
* flush wall-clock. This preserves the semantic that these timestamps track
|
|
401
|
-
* the error's occurrence, not the observability pipeline's delay.
|
|
402
|
-
*/
|
|
403
|
-
toRecordOccurrenceOp(input: RecordOccurrenceInput): AnyBulkWriteOperation<JobErrorDoc>;
|
|
404
|
-
private buildRecordOccurrencePayload;
|
|
405
|
-
topErrors(options: TopErrorsOptions): Promise<JobErrorDoc[]>;
|
|
406
|
-
}
|
|
210
|
+
type LiveControls = Map<string, JobControls>;
|
|
407
211
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Builds the bulk write operation for `recordFailure` WITHOUT executing it.
|
|
414
|
-
* Returns a single insertOne op matching the direct-call document shape
|
|
415
|
-
* bit-for-bit. Intended for the event-hooks layer (Story 1.7) to push through
|
|
416
|
-
* a `BatchWriter`. Throws synchronously on invalid input using the same error
|
|
417
|
-
* messages as `recordFailure`.
|
|
418
|
-
*/
|
|
419
|
-
toRecordFailureOp(input: RecordFailureInput): AnyBulkWriteOperation<JobFailureDoc>;
|
|
420
|
-
private buildFailureDoc;
|
|
421
|
-
private validateFailureInput;
|
|
422
|
-
listFailures(options: ListFailuresOptions): Promise<{
|
|
423
|
-
items: JobFailureDoc[];
|
|
424
|
-
total: number;
|
|
425
|
-
}>;
|
|
426
|
-
getFailure(jobId: string): Promise<JobFailureDoc | null>;
|
|
427
|
-
private serializeInputValue;
|
|
428
|
-
private capLogs;
|
|
212
|
+
interface RehydrationReport {
|
|
213
|
+
restored: number;
|
|
214
|
+
alreadyLive: number;
|
|
215
|
+
truncated: boolean;
|
|
429
216
|
}
|
|
430
217
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
* - `$currentDate { updatedAt }` — timestamp bumps every call.
|
|
450
|
-
*
|
|
451
|
-
* Metadata projection (narrow + stable — see D5.1-h):
|
|
452
|
-
* - `type`: jobConfig.type (always present in the discriminated union).
|
|
453
|
-
* - `queue`: jobConfig.queue ?? null (null = inherits defaultQueue).
|
|
454
|
-
* - `cron`: jobConfig.cron if present (token-bucket only today), else null.
|
|
455
|
-
*
|
|
456
|
-
* Additional type-specific fields (token-bucket's `rate`, distributed-etl's
|
|
457
|
-
* `steps`) are NOT extracted — BSON can't serialize the function references
|
|
458
|
-
* they contain, and the dashboard surface consumes only `type`/`queue`/`cron`
|
|
459
|
-
* in V1. Future stories can widen this projection without a schema change.
|
|
460
|
-
*
|
|
461
|
-
* Failure mode: `bulkWrite` is the only I/O. Empty input short-circuits
|
|
462
|
-
* because the driver rejects empty ops arrays.
|
|
463
|
-
*/
|
|
464
|
-
ensureEntries(jobs: Record<string, JobConfig>): Promise<void>;
|
|
465
|
-
private validateJobType;
|
|
218
|
+
interface ControlStoreParts {
|
|
219
|
+
hash: ControlHash;
|
|
220
|
+
publisher: ControlPublisher;
|
|
221
|
+
mirror: ControlMirror;
|
|
222
|
+
logger: Logger;
|
|
223
|
+
}
|
|
224
|
+
declare class ControlStore implements JobControlPlane {
|
|
225
|
+
private readonly parts;
|
|
226
|
+
constructor(parts: ControlStoreParts);
|
|
227
|
+
read(jobName: string): Promise<JobControls>;
|
|
228
|
+
write(jobName: string, patch: Partial<JobControls>): Promise<void>;
|
|
229
|
+
readAll(): Promise<LiveControls>;
|
|
230
|
+
rehydrate(): Promise<RehydrationReport>;
|
|
231
|
+
close(): Promise<void>;
|
|
232
|
+
private isPulled;
|
|
233
|
+
private writeLevers;
|
|
234
|
+
private announce;
|
|
235
|
+
private writeMirror;
|
|
466
236
|
}
|
|
467
237
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
private
|
|
481
|
-
private readonly heartbeatIntervalMs;
|
|
482
|
-
private readonly hostname;
|
|
483
|
-
private readonly pid;
|
|
484
|
-
private readonly _workerId;
|
|
485
|
-
private readonly startedAt;
|
|
486
|
-
private readonly clock;
|
|
487
|
-
private timer;
|
|
488
|
-
private started;
|
|
489
|
-
private registered;
|
|
490
|
-
constructor(repo: WorkersRepo, options?: WorkerRegistryOptions);
|
|
491
|
-
get workerId(): string;
|
|
492
|
-
registerQueue(queue: WorkerQueueEntry): Promise<void>;
|
|
493
|
-
start(): Promise<void>;
|
|
494
|
-
stop(): Promise<void>;
|
|
495
|
-
private doHeartbeat;
|
|
496
|
-
private static validateHeartbeatInterval;
|
|
497
|
-
private static validateQueueEntry;
|
|
238
|
+
declare class ControlPlane implements JobControlPlane {
|
|
239
|
+
private readonly parts;
|
|
240
|
+
private readonly cache;
|
|
241
|
+
constructor(parts: {
|
|
242
|
+
store: ControlStore;
|
|
243
|
+
channel: ControlChannel;
|
|
244
|
+
logger: Logger;
|
|
245
|
+
});
|
|
246
|
+
read(jobName: string): Promise<JobControls>;
|
|
247
|
+
write(jobName: string, patch: Partial<JobControls>): Promise<void>;
|
|
248
|
+
rehydrate(): Promise<void>;
|
|
249
|
+
close(): Promise<void>;
|
|
250
|
+
private closeQuietly;
|
|
498
251
|
}
|
|
499
252
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
253
|
+
type QueuesByName = Record<string, Queue>;
|
|
254
|
+
|
|
255
|
+
interface SpoolPurgeReport {
|
|
256
|
+
dropped: number;
|
|
257
|
+
inFlight: number;
|
|
505
258
|
}
|
|
506
259
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
260
|
+
type JobsProxy<TJobs extends Record<string, AnyJob>> = {
|
|
261
|
+
[K in keyof TJobs]: JobProxy<TJobs[K]>;
|
|
262
|
+
};
|
|
263
|
+
type JobProxy<T extends AnyJob> = T extends JobDefinition<infer TPayload, infer TResult> ? SendOrIngest<T, TPayload, TResult> & {
|
|
264
|
+
controls: ControlsOf<T>;
|
|
265
|
+
} : never;
|
|
266
|
+
type SendOrIngest<T extends AnyJob, TPayload, TResult> = T extends {
|
|
267
|
+
trigger: SpoolTriggerDeclaration;
|
|
268
|
+
} ? SpoolIngest<TPayload> : JobSend<TPayload, TResult>;
|
|
269
|
+
interface JobSend<TPayload, TResult> {
|
|
270
|
+
send(params: TPayload, options?: SendOptions): Promise<Job<TPayload, TResult>>;
|
|
271
|
+
}
|
|
272
|
+
interface SendOptions {
|
|
273
|
+
delayMs?: number;
|
|
274
|
+
priority?: number;
|
|
275
|
+
deduplicationId?: string;
|
|
276
|
+
}
|
|
277
|
+
interface SpoolIngest<TItem> {
|
|
278
|
+
push(item: TItem): Promise<string>;
|
|
279
|
+
pushMany(items: TItem[]): Promise<string[]>;
|
|
280
|
+
}
|
|
281
|
+
type ControlsOf<T extends AnyJob> = T extends {
|
|
282
|
+
trigger: SpoolTriggerDeclaration;
|
|
283
|
+
} ? SpoolFedControls : T extends {
|
|
284
|
+
trigger: CronTrigger;
|
|
285
|
+
} ? ClockFedControls : ExecutionControls;
|
|
286
|
+
interface ExecutionControls {
|
|
287
|
+
pauseExecution(): Promise<void>;
|
|
288
|
+
resumeExecution(): Promise<void>;
|
|
289
|
+
}
|
|
290
|
+
interface TriggerControls {
|
|
291
|
+
pauseTrigger(): Promise<void>;
|
|
292
|
+
resumeTrigger(): Promise<void>;
|
|
293
|
+
}
|
|
294
|
+
interface IngestControls {
|
|
295
|
+
pauseIngest(): Promise<void>;
|
|
296
|
+
resumeIngest(): Promise<void>;
|
|
297
|
+
}
|
|
298
|
+
interface ClockFedControls extends ExecutionControls, TriggerControls {
|
|
299
|
+
}
|
|
300
|
+
interface SpoolFedControls extends ExecutionControls, TriggerControls, IngestControls {
|
|
301
|
+
purgeBacklog(): Promise<SpoolPurgeReport>;
|
|
526
302
|
}
|
|
527
303
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
enabled?: boolean;
|
|
542
|
-
heartbeatIntervalMs?: number;
|
|
543
|
-
batchWriter?: {
|
|
544
|
-
maxBufferSize?: number;
|
|
545
|
-
flushIntervalMs?: number;
|
|
546
|
-
};
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
declare class RavenflowApp<TConfig extends RavenflowConfig = RavenflowConfig> {
|
|
550
|
-
protected redisConnection: ConnectionOptions;
|
|
551
|
-
protected defaultConcurrency: number;
|
|
552
|
-
protected config: TConfig;
|
|
553
|
-
protected mongoUri: string | null;
|
|
554
|
-
jobs: JobsProxy<TConfig["jobs"]>;
|
|
555
|
-
protected jobConfigs: Record<JobNames<TConfig>, JobConfig>;
|
|
556
|
-
protected queues: QueueStore;
|
|
557
|
-
protected workers: Worker[];
|
|
558
|
-
protected stallWatcher: StallWatcher | null;
|
|
559
|
-
protected workersRepo: WorkersRepo | null;
|
|
560
|
-
protected workerRegistry: WorkerRegistry | null;
|
|
561
|
-
protected jobStatsRepo: JobStatsRepo | null;
|
|
562
|
-
protected jobErrorsRepo: JobErrorsRepo | null;
|
|
563
|
-
protected jobFailuresRepo: JobFailuresRepo | null;
|
|
564
|
-
protected jobConfigsRepo: JobConfigsRepo | null;
|
|
565
|
-
protected jobStatsBatchWriter: BatchWriter<JobStatsDoc> | null;
|
|
566
|
-
protected jobErrorsBatchWriter: BatchWriter<JobErrorDoc> | null;
|
|
567
|
-
protected jobFailuresBatchWriter: BatchWriter<JobFailureDoc> | null;
|
|
568
|
-
protected monitoringInitPromise: Promise<void> | null;
|
|
569
|
-
protected readonly monitoringOptions: {
|
|
570
|
-
enabled: boolean;
|
|
571
|
-
heartbeatIntervalMs: number | undefined;
|
|
572
|
-
batchWriter: BatchWriterConfig;
|
|
573
|
-
};
|
|
574
|
-
constructor(config: TConfig, options: RavenflowAppOptions);
|
|
575
|
-
startWorker(queueName: string, options?: {
|
|
576
|
-
concurrency?: number;
|
|
577
|
-
}): Promise<void>;
|
|
578
|
-
protected initializeMonitoring(queueName: string, concurrency: number): Promise<void>;
|
|
304
|
+
declare class RavenflowClient<TConfig extends RavenflowConfig = RavenflowConfig> {
|
|
305
|
+
readonly jobs: JobsProxy<TConfig["jobs"]>;
|
|
306
|
+
protected readonly redisConnectionOptions: ConnectionOptions;
|
|
307
|
+
protected readonly mongoUri: string;
|
|
308
|
+
protected readonly mongo: MongoConnection;
|
|
309
|
+
protected readonly config: TConfig;
|
|
310
|
+
protected readonly controlPlane: ControlPlane;
|
|
311
|
+
protected readonly queues: QueuesByName;
|
|
312
|
+
protected readonly logger: Logger;
|
|
313
|
+
constructor(config: TConfig, options: {
|
|
314
|
+
redis: ConnectionOptions;
|
|
315
|
+
mongo: string;
|
|
316
|
+
});
|
|
579
317
|
close(): Promise<void>;
|
|
580
318
|
}
|
|
581
319
|
|
|
582
|
-
declare function
|
|
583
|
-
|
|
584
|
-
declare function captureJobLogs(queue: Queue, jobId: string, maxChars: number): Promise<string>;
|
|
320
|
+
declare function createRavenflowClient<TConfig extends RavenflowConfig>(config: TConfig, options: ConstructorParameters<typeof RavenflowClient>[1]): RavenflowClient<TConfig>;
|
|
585
321
|
|
|
586
|
-
interface
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}
|
|
597
|
-
declare function attachEventHooks(worker: Worker, options: EventHooksOptions): void;
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* Inlined minute-count constants. Mirrors BullMQ's `MetricsTime` enum
|
|
601
|
-
* (bullmq@5.63.1) but severs the import edge so consumers of this constant
|
|
602
|
-
* don't pull BullMQ into their bundle. Values are pure math (minutes in
|
|
603
|
-
* the named window) and therefore stable across BullMQ versions. Lives
|
|
604
|
-
* here instead of `index.ts` to avoid an import cycle
|
|
605
|
-
* (`index.ts` → `./app/index` → `./app/app` → `worker-manager`).
|
|
606
|
-
*/
|
|
607
|
-
declare const METRICS_TIME: {
|
|
608
|
-
readonly ONE_MINUTE: 1;
|
|
609
|
-
readonly FIVE_MINUTES: 5;
|
|
610
|
-
readonly FIFTEEN_MINUTES: 15;
|
|
611
|
-
readonly THIRTY_MINUTES: 30;
|
|
612
|
-
readonly ONE_HOUR: 60;
|
|
613
|
-
readonly ONE_DAY: 1440;
|
|
614
|
-
readonly ONE_WEEK: 10080;
|
|
615
|
-
readonly TWO_WEEKS: 20160;
|
|
616
|
-
readonly ONE_MONTH: 80640;
|
|
617
|
-
};
|
|
618
|
-
/**
|
|
619
|
-
* Default BullMQ metrics configuration applied to every ravenflow-managed
|
|
620
|
-
* Worker. Enables the per-minute data-point collection read by the
|
|
621
|
-
* ravenflow-dashboard Jobs-per-Second indicator (Epic 4 Story 4.2).
|
|
622
|
-
*
|
|
623
|
-
* Without this default, BullMQ's `collectMetrics` Lua function is a no-op on
|
|
624
|
-
* every `moveToFinished` — `queue.getMetrics('completed')` would return
|
|
625
|
-
* `{ meta: { count: 0 }, data: [] }` indefinitely for Ravenflow-managed
|
|
626
|
-
* queues (silent false-negative under real throughput).
|
|
627
|
-
*
|
|
628
|
-
* `ONE_WEEK = 10_080` minutes ≈ 7 days of minute-resolution history at a
|
|
629
|
-
* Redis footprint of ~10 KB/queue/week. Callers may override via the
|
|
630
|
-
* `workerOpts.metrics` parameter on `createWorker` (e.g. to disable
|
|
631
|
-
* collection or pick a shorter window).
|
|
632
|
-
*
|
|
633
|
-
* Frozen so the exported reference cannot be mutated by a caller (shared
|
|
634
|
-
* default would otherwise bleed globally across `createWorker` calls).
|
|
635
|
-
*/
|
|
636
|
-
declare const DEFAULT_WORKER_METRICS: NonNullable<WorkerOptions["metrics"]>;
|
|
637
|
-
|
|
638
|
-
/**
|
|
639
|
-
* Delay (ms) applied to jobs whose jobType is `enabled: false`. After this
|
|
640
|
-
* window BullMQ returns the job to the `waiting` set and a worker picks it
|
|
641
|
-
* up again; the gate re-evaluates. When the jobType re-enables the next
|
|
642
|
-
* attempt passes the check and dispatches normally.
|
|
643
|
-
*
|
|
644
|
-
* 60 seconds strikes the balance between "pause takes effect quickly" and
|
|
645
|
-
* "don't hammer Redis / Mongo with redefer churn" (D5.1-b).
|
|
646
|
-
*/
|
|
647
|
-
declare const DISABLED_JOB_DEFER_DELAY_MS = 60000;
|
|
648
|
-
/**
|
|
649
|
-
* Worker-side defer gate for disabled jobTypes (Story 5.1 D5.1-b).
|
|
650
|
-
*
|
|
651
|
-
* When the jobType's `enabled` flag is `false` in `job_configs`, this
|
|
652
|
-
* helper moves the job to `delayed` with a +60s timestamp, increments
|
|
653
|
-
* the cumulative `disabledDeferCount` on `job.progress`, and throws
|
|
654
|
-
* `DelayedError` — the BullMQ-canonical signal for "I moved this job to
|
|
655
|
-
* delayed, don't mark completed/failed" (verified against
|
|
656
|
-
* node_modules/bullmq/dist/esm/classes/errors/delayed-error.d.ts:9
|
|
657
|
-
* bullmq@5.63.1).
|
|
658
|
-
*
|
|
659
|
-
* When the jobType is enabled (or no row exists — default is `true`),
|
|
660
|
-
* this is a no-op and the caller proceeds to normal dispatch.
|
|
661
|
-
*
|
|
662
|
-
* The `token` argument is the processor lambda's 2nd BullMQ argument
|
|
663
|
-
* (verified against node_modules/bullmq/dist/esm/classes/job.d.ts:444
|
|
664
|
-
* bullmq@5.63.1 — moveToDelayed(timestamp, token?) — passing undefined
|
|
665
|
-
* is accepted but may fail under lock contention with renewLock).
|
|
666
|
-
*/
|
|
667
|
-
declare function deferIfDisabled(job: Job, jobConfigs: Record<string, JobConfig>, jobConfigsRepo: JobConfigsRepo, token: string | undefined): Promise<void>;
|
|
322
|
+
interface RavenflowWorkerOptions {
|
|
323
|
+
redis: ConnectionOptions;
|
|
324
|
+
mongo: string;
|
|
325
|
+
queue: string;
|
|
326
|
+
concurrency?: number;
|
|
327
|
+
withdrawal?: WithdrawalOptions;
|
|
328
|
+
}
|
|
329
|
+
interface WithdrawalOptions {
|
|
330
|
+
afterMs?: number;
|
|
331
|
+
onWithdraw?: (reason: string) => void | Promise<void>;
|
|
332
|
+
}
|
|
668
333
|
|
|
669
|
-
declare
|
|
334
|
+
declare class RavenflowWorker {
|
|
335
|
+
private readonly config;
|
|
336
|
+
private readonly options;
|
|
337
|
+
private readonly jobs;
|
|
338
|
+
private readonly logger;
|
|
339
|
+
private serving;
|
|
340
|
+
private starting;
|
|
341
|
+
private closing;
|
|
342
|
+
constructor(config: RavenflowConfig, options: RavenflowWorkerOptions);
|
|
343
|
+
start(): Promise<void>;
|
|
344
|
+
close(): Promise<void>;
|
|
345
|
+
private serveOrStop;
|
|
346
|
+
private stopServing;
|
|
347
|
+
private refuseASecondStart;
|
|
348
|
+
private openServing;
|
|
349
|
+
private buildControlPlaneReader;
|
|
350
|
+
private buildJobResultsRecorder;
|
|
351
|
+
private buildJobResultsAggregator;
|
|
352
|
+
private buildSpoolFeeder;
|
|
353
|
+
private buildMongoWatch;
|
|
354
|
+
private beginAWithdrawal;
|
|
355
|
+
private serve;
|
|
356
|
+
private openRecorder;
|
|
357
|
+
private sayJobResultsAreNotRecorded;
|
|
358
|
+
private takeJobs;
|
|
359
|
+
}
|
|
670
360
|
|
|
671
|
-
declare function
|
|
361
|
+
declare function createRavenflowWorker(config: RavenflowConfig, options: RavenflowWorkerOptions): RavenflowWorker;
|
|
672
362
|
|
|
673
|
-
export {
|
|
363
|
+
export { type JobDefinition, RavenflowClient, type RavenflowConfig, RavenflowWorker, type RavenflowWorkerOptions, createRavenflowClient, createRavenflowWorker, defineConfig, defineJob };
|