Skip to content

Latest commit

 

History

History
60 lines (45 loc) · 1.79 KB

File metadata and controls

60 lines (45 loc) · 1.79 KB

ADR-001: Threaded Handler Execution

Status: Accepted
Date: 2025-12-29

Context

Durable functions need to suspend execution immediately at suspension points (wait, callback, retry). The system must return PENDING status to Lambda without waiting for the handler to complete.

public String handleRequest(MyInput input, DurableContext context) {
    var result1 = context.step("step1", stepCtx -> "first");
    context.wait(null, Duration.ofHours(1)); // Should suspend HERE
    var result2 = context.step("step2", stepCtx -> "second"); // Don't wait for this
    return result1 + result2;
}

Decision

Run the handler in a background thread and race two futures:

var handlerFuture = CompletableFuture.supplyAsync(stepCtx -> handler.apply(input, context), executor);
var suspendFuture = executionManager.getSuspendExecutionFuture();

CompletableFuture.anyOf(handlerFuture, suspendFuture).join();

if (suspendFuture.isDone()) {
    return DurableExecutionOutput.pending();
}

Alternatives Considered

Exception-Based Control Flow

try {
    O result = handler.apply(input, context);
    return DurableExecutionOutput.success(result);
} catch (SuspendExecutionException e) {
    return DurableExecutionOutput.pending();
}

Rejected because:

  1. Users can catch and suppress the exception
  2. Requires two-level exception handling (operation wants suspend vs. ExecutionManager confirms suspend)
  3. Exceptions for control flow is an anti-pattern

Consequences

Positive:

  • Immediate suspension without waiting for handler completion
  • Clean separation: suspension decision is in ExecutionManager, not scattered in operations
  • Users cannot accidentally suppress suspension

Negative:

  • More complex threading model
  • Requires thread tracking in ExecutionManager