@bobtail.software/b-durable 1.0.5 → 1.0.7
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 +1 -232
- package/dist/compiler/cli.mjs +46 -703
- package/dist/index.d.mts +174 -26
- package/dist/index.mjs +86 -546
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import Redis from 'ioredis';
|
|
2
2
|
import ms from 'ms';
|
|
3
3
|
|
|
4
|
+
interface Logger {
|
|
5
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
6
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
7
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
8
|
+
debug(message: string, meta?: Record<string, unknown>): void;
|
|
9
|
+
}
|
|
10
|
+
interface WorkflowStateInfo<TInput = unknown, TOutput = unknown> {
|
|
11
|
+
workflowId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
version: string;
|
|
14
|
+
status: string;
|
|
15
|
+
step: number;
|
|
16
|
+
input: TInput;
|
|
17
|
+
output?: TOutput;
|
|
18
|
+
state: Record<string, unknown>;
|
|
19
|
+
error?: string;
|
|
20
|
+
createdAt?: number;
|
|
21
|
+
updatedAt?: number;
|
|
22
|
+
pendingTask?: {
|
|
23
|
+
name: string;
|
|
24
|
+
attempts: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
4
27
|
interface WorkflowState {
|
|
5
28
|
tryCatchStack?: {
|
|
6
29
|
catchStep?: number;
|
|
@@ -14,7 +37,17 @@ interface WorkflowContext<TInput = unknown> {
|
|
|
14
37
|
input: TInput;
|
|
15
38
|
state: WorkflowState;
|
|
16
39
|
result?: unknown;
|
|
17
|
-
log: (message: string) => void;
|
|
40
|
+
log: (message: string, meta?: Record<string, unknown>) => void;
|
|
41
|
+
}
|
|
42
|
+
interface RetryOptions {
|
|
43
|
+
/** Número máximo de intentos. Infinity para reintentar siempre. Por defecto: 3 */
|
|
44
|
+
maxAttempts?: number;
|
|
45
|
+
/** Tiempo de espera antes del primer reintento (ej: '1s'). Por defecto: '1s' */
|
|
46
|
+
initialInterval?: ms.StringValue;
|
|
47
|
+
/** Coeficiente de multiplicación para backoff exponencial. Por defecto: 2 */
|
|
48
|
+
backoffCoefficient?: number;
|
|
49
|
+
/** Tiempo máximo de espera entre reintentos (ej: '1h'). Por defecto: '1h' */
|
|
50
|
+
maxInterval?: ms.StringValue;
|
|
18
51
|
}
|
|
19
52
|
type Instruction<TOutput = unknown> = {
|
|
20
53
|
type: 'SCHEDULE_TASK';
|
|
@@ -25,55 +58,147 @@ type Instruction<TOutput = unknown> = {
|
|
|
25
58
|
type: 'SCHEDULE_SLEEP';
|
|
26
59
|
duration: ms.StringValue;
|
|
27
60
|
} | {
|
|
28
|
-
type: '
|
|
29
|
-
|
|
61
|
+
type: 'WAIT_FOR_SIGNAL';
|
|
62
|
+
signalName: string;
|
|
30
63
|
} | {
|
|
31
64
|
type: 'EXECUTE_SUBWORKFLOW';
|
|
32
65
|
workflowName: string;
|
|
33
66
|
input: unknown;
|
|
67
|
+
} | {
|
|
68
|
+
type: 'EMIT_EVENT';
|
|
69
|
+
eventName: string;
|
|
70
|
+
payload: unknown;
|
|
34
71
|
} | {
|
|
35
72
|
type: 'COMPLETE';
|
|
36
73
|
result: TOutput;
|
|
37
74
|
};
|
|
38
|
-
interface DurableFunction<TInput = unknown, TOutput = unknown,
|
|
75
|
+
interface DurableFunction<TInput = unknown, TOutput = unknown, TSignals = Record<string, never>, // INPUT: Señales que el workflow puede RECIBIR
|
|
76
|
+
TEvents = Record<string, never>> {
|
|
39
77
|
__isDurable: true;
|
|
40
78
|
name: string;
|
|
79
|
+
version: string;
|
|
80
|
+
retryOptions?: RetryOptions;
|
|
41
81
|
execute: (context: WorkflowContext<TInput>) => Promise<Instruction<TOutput>>;
|
|
82
|
+
_TSignals?: TSignals;
|
|
42
83
|
_TEvents?: TEvents;
|
|
43
84
|
}
|
|
44
|
-
|
|
45
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Transforma un mapa de eventos en props de listeners.
|
|
87
|
+
* Ejemplo: { started: { id: string } } => { onStarted?: (payload: { id: string }) => void }
|
|
88
|
+
*/
|
|
89
|
+
type WorkflowEventListeners<TEvents> = {
|
|
90
|
+
[K in keyof TEvents as `on${Capitalize<string & K>}`]?: (payload: TEvents[K]) => void;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Representa cualquier evento que sale del workflow, ya sea definido por el usuario
|
|
94
|
+
* o por el sistema (completado/fallido).
|
|
95
|
+
*/
|
|
96
|
+
type WorkflowEvent<TEvents, TOutput> = {
|
|
97
|
+
[K in keyof TEvents]: {
|
|
98
|
+
name: K;
|
|
99
|
+
payload: TEvents[K];
|
|
100
|
+
};
|
|
101
|
+
}[keyof TEvents] | {
|
|
102
|
+
name: 'workflow:completed';
|
|
103
|
+
payload: TOutput;
|
|
104
|
+
} | {
|
|
105
|
+
name: 'workflow:failed';
|
|
106
|
+
payload: {
|
|
107
|
+
message: string;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Utilidad para "aplanar" intersecciones de tipos.
|
|
112
|
+
* Esto fuerza a TypeScript a computar el objeto final inmediatamente,
|
|
113
|
+
* permitiendo que la inferencia contextual de los argumentos funcione correctamente.
|
|
114
|
+
*/
|
|
115
|
+
type Compute<T> = {
|
|
116
|
+
[K in keyof T]: T[K];
|
|
117
|
+
} & unknown;
|
|
118
|
+
/**
|
|
119
|
+
* Opciones para iniciar el workflow. Combina input estándar + listeners dinámicos.
|
|
120
|
+
*/
|
|
121
|
+
type StartOptions<TInput, TEvents> = Compute<{
|
|
46
122
|
input: TInput;
|
|
47
123
|
workflowId?: string;
|
|
124
|
+
} & WorkflowEventListeners<TEvents>>;
|
|
125
|
+
interface StartedWorkflowHandle {
|
|
126
|
+
workflowId: string;
|
|
127
|
+
unsubscribe: () => Promise<void>;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Handle para interactuar con un workflow en ejecución.
|
|
131
|
+
*/
|
|
132
|
+
interface WorkflowHandle<TSignals, TEvents, TOutput> {
|
|
133
|
+
workflowId: string;
|
|
134
|
+
/**
|
|
135
|
+
* Envía una señal (INPUT) al workflow.
|
|
136
|
+
* @param name Nombre de la señal (definido en TSignals).
|
|
137
|
+
* @param payload Datos de la señal.
|
|
138
|
+
*/
|
|
139
|
+
signal: <K extends keyof TSignals>(name: K, payload: TSignals[K]) => Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Suscribe un callback a un evento específico (OUTPUT).
|
|
142
|
+
* @param eventName Nombre del evento (definido en TEvents).
|
|
143
|
+
* @param handler Función que recibe el payload.
|
|
144
|
+
*/
|
|
145
|
+
on: <K extends keyof TEvents>(eventName: K, handler: (payload: TEvents[K]) => void) => Promise<{
|
|
146
|
+
unsubscribe: () => void;
|
|
147
|
+
}>;
|
|
148
|
+
/**
|
|
149
|
+
* Suscribe un callback a TODOS los eventos (incluyendo sistema).
|
|
150
|
+
* Útil para logging o debug.
|
|
151
|
+
*/
|
|
152
|
+
subscribe: (handler: (event: WorkflowEvent<TEvents, TOutput>) => void) => Promise<{
|
|
153
|
+
unsubscribe: () => void;
|
|
154
|
+
}>;
|
|
48
155
|
}
|
|
156
|
+
declare class WorkflowCancellationError extends Error {
|
|
157
|
+
readonly isCancellation = true;
|
|
158
|
+
constructor(message: string);
|
|
159
|
+
}
|
|
160
|
+
|
|
49
161
|
declare class DurableRuntime {
|
|
50
162
|
private durableFns;
|
|
51
163
|
private repo;
|
|
52
164
|
private workerId;
|
|
53
165
|
private isRunning;
|
|
54
166
|
private schedulerInterval;
|
|
167
|
+
private heartbeatInterval;
|
|
55
168
|
private readonly sourceRoot;
|
|
169
|
+
private readonly pollingInterval;
|
|
170
|
+
private readonly logger;
|
|
171
|
+
private readonly maxTaskRetries;
|
|
56
172
|
constructor(options: {
|
|
57
173
|
sourceRoot: string;
|
|
174
|
+
retention?: ms.StringValue;
|
|
175
|
+
pollingInterval?: number;
|
|
176
|
+
logger?: Logger;
|
|
58
177
|
});
|
|
59
|
-
|
|
178
|
+
getState(workflowId: string): Promise<WorkflowStateInfo | null>;
|
|
179
|
+
start<TInput, TOutput, TSignals, TEvents>(durableFn: DurableFunction<TInput, TOutput, TSignals, TEvents>, options: StartOptions<TInput, TEvents>, parentId?: string): Promise<StartedWorkflowHandle>;
|
|
60
180
|
private scheduleExecution;
|
|
61
181
|
private _executeStep;
|
|
62
182
|
private handleInstruction;
|
|
63
183
|
private handleFailure;
|
|
64
184
|
private resumeParentWorkflow;
|
|
65
185
|
private propagateFailureToParent;
|
|
66
|
-
|
|
186
|
+
signal<T>(workflowId: string, signalName: string, payload: T): Promise<void>;
|
|
187
|
+
cancel(workflowId: string, reason: string): Promise<void>;
|
|
67
188
|
private startScheduler;
|
|
189
|
+
private checkDelayedTasks;
|
|
190
|
+
private checkSleepers;
|
|
191
|
+
private reapDeadWorkers;
|
|
192
|
+
private startHeartbeat;
|
|
68
193
|
private startWorker;
|
|
69
|
-
run(durableFns: Map<string, DurableFunction<unknown>>): void;
|
|
70
|
-
stop(): void
|
|
194
|
+
run(durableFns: Map<string, DurableFunction<unknown, unknown, unknown, unknown>>): void;
|
|
195
|
+
stop(): Promise<void>;
|
|
71
196
|
}
|
|
72
197
|
|
|
73
198
|
/**
|
|
74
199
|
* El contexto de ejecución proporcionado a cada workflow, con métodos de durabilidad tipados.
|
|
75
200
|
*/
|
|
76
|
-
interface DurableContext<TEvents = Record<string, never>> extends Pick<WorkflowContext, 'log' | 'workflowId'> {
|
|
201
|
+
interface DurableContext<TEvents = Record<string, never>, TSignals = Record<string, never>> extends Pick<WorkflowContext, 'log' | 'workflowId'> {
|
|
77
202
|
/**
|
|
78
203
|
* Pausa la ejecución del workflow de manera duradera.
|
|
79
204
|
* @param duration Una cadena de tiempo como '2 days', '10h', '7s'.
|
|
@@ -92,41 +217,64 @@ interface DurableContext<TEvents = Record<string, never>> extends Pick<WorkflowC
|
|
|
92
217
|
* @param input La entrada para el sub-workflow.
|
|
93
218
|
* @returns Una promesa que se resuelve con el resultado del sub-workflow.
|
|
94
219
|
*/
|
|
95
|
-
bExecute<TInput, TOutput, TWorkflowEvents
|
|
220
|
+
bExecute<TInput, TOutput, TWorkflowEvents, TWorkflowSignals>(workflow: DurableFunction<TInput, TOutput, TWorkflowEvents, TWorkflowSignals>, input: TInput): Promise<TOutput>;
|
|
221
|
+
/**
|
|
222
|
+
* Emite una señal o notificación con un payload desde el workflow.
|
|
223
|
+
* Esta operación es duradera pero no bloquea la ejecución. El workflow continúa inmediatamente después.
|
|
224
|
+
* El nombre de la señal y el tipo del payload son validados contra el contrato de señales del workflow.
|
|
225
|
+
* @param signalName El nombre de la señal.
|
|
226
|
+
* @param payload Los datos a enviar con la señal.
|
|
227
|
+
*/
|
|
228
|
+
bSignal<K extends keyof TSignals>(signalName: K, payload: TSignals[K]): Promise<void>;
|
|
96
229
|
}
|
|
97
|
-
type DurableWorkflowFn<TInput, TOutput, TEvents = Record<string, never>> = (input: TInput, context: DurableContext<TEvents>) => Promise<TOutput>;
|
|
98
|
-
interface DurableWorkflowDef<TInput, TOutput, TEvents = Record<string, never>> {
|
|
230
|
+
type DurableWorkflowFn<TInput, TOutput, TEvents = Record<string, never>, TSignals = Record<string, never>> = (input: TInput, context: DurableContext<TEvents, TSignals>) => Promise<TOutput>;
|
|
231
|
+
interface DurableWorkflowDef<TInput, TOutput, TEvents = Record<string, never>, TSignals = Record<string, never>> {
|
|
99
232
|
/**
|
|
100
233
|
* La función async que contiene la lógica del workflow.
|
|
101
234
|
*/
|
|
102
|
-
workflow: DurableWorkflowFn<TInput, TOutput, TEvents>;
|
|
235
|
+
workflow: DurableWorkflowFn<TInput, TOutput, TEvents, TSignals>;
|
|
236
|
+
/**
|
|
237
|
+
* Versión del workflow. Se utiliza para identificar versiones de un workflow.
|
|
238
|
+
*/
|
|
239
|
+
version: string;
|
|
240
|
+
/**
|
|
241
|
+
* Política de reintento para las tareas ejecutadas por este workflow.
|
|
242
|
+
* Si falla una tarea, se aplicará esta configuración.
|
|
243
|
+
*/
|
|
244
|
+
retryOptions?: RetryOptions;
|
|
103
245
|
}
|
|
104
246
|
/**
|
|
105
247
|
* Marcador para que el compilador identifique y transforme una función en un workflow durable.
|
|
106
248
|
* Esta función es un passthrough en tiempo de ejecución, su único propósito es para el análisis estático.
|
|
107
249
|
*/
|
|
108
|
-
declare const bDurable: <TInput = any, TOutput = any, TEvents = Record<string, never>>(def: DurableWorkflowDef<TInput, TOutput, TEvents>) => DurableFunction<TInput, TOutput, TEvents>;
|
|
250
|
+
declare const bDurable: <TInput = any, TOutput = any, TEvents = Record<string, never>, TSignals = Record<string, never>>(def: DurableWorkflowDef<TInput, TOutput, TEvents, TSignals>) => DurableFunction<TInput, TOutput, TEvents, TSignals>;
|
|
109
251
|
|
|
110
252
|
interface BDurableAPI {
|
|
111
|
-
|
|
253
|
+
/**
|
|
254
|
+
* Inicia un workflow durable.
|
|
255
|
+
* Permite definir listeners de eventos inmediatamente en las opciones (ej: { onProgress: ... })
|
|
256
|
+
* para evitar condiciones de carrera.
|
|
257
|
+
*/
|
|
258
|
+
start: <TInput, TOutput, TSignals, TEvents>(durableFn: DurableFunction<TInput, TOutput, TSignals, TEvents>, options: StartOptions<TInput, TEvents>) => Promise<StartedWorkflowHandle>;
|
|
112
259
|
stop: () => void;
|
|
113
260
|
runtime: DurableRuntime;
|
|
261
|
+
cancel: (workflowId: string, reason: string) => Promise<void>;
|
|
262
|
+
getState: (workflowId: string) => Promise<WorkflowStateInfo | null>;
|
|
114
263
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* @param durableFn La definición del workflow al que se le enviará el evento. Se usa para la inferencia de tipos.
|
|
118
|
-
* @param workflowId El ID del workflow al que se le enviará el evento.
|
|
119
|
-
* @param eventName El nombre del evento. Será autocompletado por el editor.
|
|
120
|
-
* @param payload La carga útil del evento. El tipo debe coincidir con el definido para `eventName`.
|
|
264
|
+
* Obtiene un "handle" para una instancia de workflow existente.
|
|
265
|
+
* Permite enviar señales (Input) y escuchar eventos (Output).
|
|
121
266
|
*/
|
|
122
|
-
|
|
267
|
+
getHandle: <TInput, TOutput, TSignals, TEvents>(durableFn: DurableFunction<TInput, TOutput, TSignals, TEvents>, workflowId: string) => WorkflowHandle<TSignals, TEvents, TOutput>;
|
|
123
268
|
}
|
|
124
269
|
interface InitializeOptions {
|
|
125
|
-
durableFunctions: Map<string, DurableFunction<unknown, unknown>>;
|
|
270
|
+
durableFunctions: Map<string, DurableFunction<unknown, unknown, any, any>>;
|
|
126
271
|
sourceRoot: string;
|
|
127
272
|
redisClient: Redis;
|
|
128
273
|
blockingRedisClient: Redis;
|
|
274
|
+
retention?: ms.StringValue;
|
|
275
|
+
pollingInterval?: number;
|
|
276
|
+
logger?: Logger;
|
|
129
277
|
}
|
|
130
278
|
declare function bDurableInitialize(options: InitializeOptions): BDurableAPI;
|
|
131
279
|
|
|
132
|
-
export { type BDurableAPI, type DurableFunction, type Instruction, type StartOptions, type WorkflowContext, type WorkflowState, bDurable, bDurableInitialize };
|
|
280
|
+
export { type BDurableAPI, type DurableFunction, type Instruction, type Logger, type RetryOptions, type StartOptions, type StartedWorkflowHandle, WorkflowCancellationError, type WorkflowContext, type WorkflowEvent, type WorkflowEventListeners, type WorkflowHandle, type WorkflowState, type WorkflowStateInfo, bDurable, bDurableInitialize };
|