|
| 1 | +# ADR-001: Threaded Handler Execution |
| 2 | + |
| 3 | +**Status:** Accepted |
| 4 | +**Date:** 2025-12-29 |
| 5 | + |
| 6 | +## Context |
| 7 | + |
| 8 | +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. |
| 9 | + |
| 10 | +```java |
| 11 | +public String handleRequest(MyInput input, DurableContext context) { |
| 12 | + var result1 = context.step("step1", () -> "first"); |
| 13 | + context.wait(Duration.ofHours(1)); // Should suspend HERE |
| 14 | + var result2 = context.step("step2", () -> "second"); // Don't wait for this |
| 15 | + return result1 + result2; |
| 16 | +} |
| 17 | +``` |
| 18 | + |
| 19 | +## Decision |
| 20 | + |
| 21 | +Run the handler in a background thread and race two futures: |
| 22 | + |
| 23 | +```java |
| 24 | +var handlerFuture = CompletableFuture.supplyAsync(() -> handler.apply(input, context), executor); |
| 25 | +var suspendFuture = executionManager.getSuspendExecutionFuture(); |
| 26 | + |
| 27 | +CompletableFuture.anyOf(handlerFuture, suspendFuture).join(); |
| 28 | + |
| 29 | +if (suspendFuture.isDone()) { |
| 30 | + return DurableExecutionOutput.pending(); |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +## Alternatives Considered |
| 35 | + |
| 36 | +### Exception-Based Control Flow |
| 37 | +```java |
| 38 | +try { |
| 39 | + O result = handler.apply(input, context); |
| 40 | + return DurableExecutionOutput.success(result); |
| 41 | +} catch (SuspendExecutionException e) { |
| 42 | + return DurableExecutionOutput.pending(); |
| 43 | +} |
| 44 | +``` |
| 45 | + |
| 46 | +**Rejected because:** |
| 47 | +1. Users can catch and suppress the exception |
| 48 | +2. Requires two-level exception handling (operation wants suspend vs. ExecutionManager confirms suspend) |
| 49 | +3. Exceptions for control flow is an anti-pattern |
| 50 | + |
| 51 | +## Consequences |
| 52 | + |
| 53 | +**Positive:** |
| 54 | +- Immediate suspension without waiting for handler completion |
| 55 | +- Clean separation: suspension decision is in ExecutionManager, not scattered in operations |
| 56 | +- Users cannot accidentally suppress suspension |
| 57 | + |
| 58 | +**Negative:** |
| 59 | +- More complex threading model |
| 60 | +- Requires thread tracking in ExecutionManager |
0 commit comments