Skip to content

Commit 77953cd

Browse files
added task features
1 parent 956aa0b commit 77953cd

3 files changed

Lines changed: 70 additions & 5 deletions

File tree

packages/jobs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@durable-effect/jobs",
3-
"version": "0.0.1-next.7",
3+
"version": "0.0.1-next.8",
44
"type": "module",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",

packages/jobs/src/handlers/task/context.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ export function createTaskExecuteContext<S>(
199199

200200
/**
201201
* Create TaskIdleContext for onIdle handler.
202+
* Full parity with TaskEventContext/TaskExecuteContext.
202203
*/
203204
export function createTaskIdleContext<S>(
204205
stateHolder: TaskStateHolder<S>,
@@ -212,15 +213,37 @@ export function createTaskIdleContext<S>(
212213
const scheduling = createSchedulingEffects(scheduleHolder, getScheduledFromStorage);
213214

214215
return {
216+
// State access
215217
state: stateHolder.dirty
216218
? Effect.succeed(stateHolder.current)
217219
: getState(),
218220

219-
schedule: scheduling.schedule,
221+
// State mutations
222+
setState: (state: S): Effect.Effect<void, never, never> =>
223+
Effect.sync(() => {
224+
stateHolder.current = state;
225+
stateHolder.dirty = true;
226+
}),
220227

228+
updateState: (fn: (current: S) => S): Effect.Effect<void, never, never> =>
229+
Effect.gen(function* () {
230+
const current = stateHolder.dirty
231+
? stateHolder.current
232+
: yield* getState();
233+
if (current !== null) {
234+
stateHolder.current = fn(current);
235+
stateHolder.dirty = true;
236+
}
237+
}),
238+
239+
// Scheduling (full access)
240+
...scheduling,
241+
242+
// Cleanup
221243
terminate: (): Effect.Effect<never, never, never> =>
222244
Effect.fail(new TerminateSignal({ reason: "terminate", purgeState: true })) as Effect.Effect<never, never, never>,
223245

246+
// Metadata
224247
instanceId,
225248
jobName,
226249
idleReason,
@@ -229,6 +252,7 @@ export function createTaskIdleContext<S>(
229252

230253
/**
231254
* Create TaskErrorContext for onError handler.
255+
* Full parity with TaskEventContext/TaskExecuteContext.
232256
*/
233257
export function createTaskErrorContext<S>(
234258
stateHolder: TaskStateHolder<S>,
@@ -242,10 +266,18 @@ export function createTaskErrorContext<S>(
242266
const scheduling = createSchedulingEffects(scheduleHolder, getScheduledFromStorage);
243267

244268
return {
269+
// State access
245270
state: stateHolder.dirty
246271
? Effect.succeed(stateHolder.current)
247272
: getState(),
248273

274+
// State mutations
275+
setState: (state: S): Effect.Effect<void, never, never> =>
276+
Effect.sync(() => {
277+
stateHolder.current = state;
278+
stateHolder.dirty = true;
279+
}),
280+
249281
updateState: (fn: (current: S) => S): Effect.Effect<void, never, never> =>
250282
Effect.gen(function* () {
251283
const current = stateHolder.dirty
@@ -257,11 +289,14 @@ export function createTaskErrorContext<S>(
257289
}
258290
}),
259291

260-
schedule: scheduling.schedule,
292+
// Scheduling (full access)
293+
...scheduling,
261294

295+
// Cleanup
262296
terminate: (): Effect.Effect<never, never, never> =>
263297
Effect.fail(new TerminateSignal({ reason: "terminate", purgeState: true })) as Effect.Effect<never, never, never>,
264298

299+
// Metadata
265300
instanceId,
266301
jobName,
267302
errorSource,

packages/jobs/src/registry/types.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,16 +613,32 @@ export interface TaskExecuteContext<S> {
613613
* Context provided to task onIdle handler.
614614
*
615615
* Called when either onEvent or execute completes without scheduling
616-
* another execution. Use this to schedule cleanup or maintenance.
616+
* another execution. Use this to update state, schedule cleanup, or terminate.
617617
*/
618618
export interface TaskIdleContext<S> {
619+
// State access
619620
/** Get current state */
620621
readonly state: Effect.Effect<S | null, never, never>;
622+
623+
// State mutations
624+
/** Replace the entire state */
625+
readonly setState: (state: S) => Effect.Effect<void, never, never>;
626+
/** Update state via transformation function (no-op if state is null) */
627+
readonly updateState: (fn: (current: S) => S) => Effect.Effect<void, never, never>;
628+
629+
// Scheduling
621630
/** Schedule execution (e.g., for delayed cleanup) */
622631
readonly schedule: (when: Duration.DurationInput | number | Date) => Effect.Effect<void, never, never>;
632+
/** Cancel any scheduled execution */
633+
readonly cancelSchedule: () => Effect.Effect<void, never, never>;
634+
/** Get the currently scheduled execution time (null if none) */
635+
readonly getScheduledTime: () => Effect.Effect<number | null, never, never>;
636+
637+
// Cleanup
623638
/** Terminate the task immediately - cancel alarms and delete all state */
624639
readonly terminate: () => Effect.Effect<never, never, never>;
625640

641+
// Metadata
626642
/** The unique instance ID for this task */
627643
readonly instanceId: string;
628644
/** The name of this job (as registered) */
@@ -635,18 +651,32 @@ export interface TaskIdleContext<S> {
635651
* Context provided to task onError handler.
636652
*
637653
* Called when onEvent or execute throws an error.
638-
* Use this to log errors, update state, or schedule retries.
654+
* Use this to log errors, update state, schedule retries, or terminate.
639655
*/
640656
export interface TaskErrorContext<S> {
657+
// State access
641658
/** Get current state */
642659
readonly state: Effect.Effect<S | null, never, never>;
660+
661+
// State mutations
662+
/** Replace the entire state */
663+
readonly setState: (state: S) => Effect.Effect<void, never, never>;
643664
/** Update state (e.g., to track error count) */
644665
readonly updateState: (fn: (current: S) => S) => Effect.Effect<void, never, never>;
666+
667+
// Scheduling
645668
/** Schedule execution (e.g., for retry) */
646669
readonly schedule: (when: Duration.DurationInput | number | Date) => Effect.Effect<void, never, never>;
670+
/** Cancel any scheduled execution */
671+
readonly cancelSchedule: () => Effect.Effect<void, never, never>;
672+
/** Get the currently scheduled execution time (null if none) */
673+
readonly getScheduledTime: () => Effect.Effect<number | null, never, never>;
674+
675+
// Cleanup
647676
/** Terminate the task immediately - cancel alarms and delete all state */
648677
readonly terminate: () => Effect.Effect<never, never, never>;
649678

679+
// Metadata
650680
/** The unique instance ID for this task */
651681
readonly instanceId: string;
652682
/** The name of this job (as registered) */

0 commit comments

Comments
 (0)