thefrontside / thefrontside/effectionx
Add TimeoutError and context-based timeout configuration to @effectionx/timebox
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 12
- Forks
- 4
- Avg merge
- 3h 17m
- Merged PRs (30d)
- 1
Description
Summary
Currently @effectionx/timebox returns a discriminated union (Timeboxed<T>) that callers must check. When callers want to throw on timeout, they must create their own error with a custom message. This leads to inconsistent error handling across the codebase.
Current Behavior
const result = yield* timebox(5000, doWork);
if (result.timeout) {
throw new Error(`Operation timed out after 5000ms`); // Custom error each time
}
return result.value;
Proposed Improvements
1. Export a typed TimeoutError
Add a dedicated error class that callers can use and catch:
export class TimeoutError extends Error {
readonly timeout: true = true;
readonly duration: number;
readonly start: DOMHighResTimeStamp;
readonly end: DOMHighResTimeStamp;
constructor(message: string, metadata: { duration: number; start: number; end: number }) {
super(message);
this.name = "TimeoutError";
this.duration = metadata.duration;
this.start = metadata.start;
this.end = metadata.end;
}
}
This allows:
try {
yield* someOperation();
} catch (e) {
if (e instanceof TimeoutError) {
// Handle timeout specifically
}
}
2. Add a throwing variant (optional)
Consider adding timeboxOrThrow that throws TimeoutError instead of returning a union:
// Returns T directly, throws TimeoutError on timeout
export function timeboxOrThrow<T>(
limitMS: number,
operation: () => Operation<T>
): Operation<T>
3. Context-based timeout configuration
Allow timeout to be configured via effection Context, enabling scope-based defaults:
import { createContext } from "effection";
export const TimeoutContext = createContext<number | undefined>("timeout");
// In a scope:
yield* TimeoutContext.set(5000);
// Later, nested operations can read the default:
const timeout = yield* TimeoutContext.get();
This enables patterns like:
// Set default timeout for all operations in this scope
yield* TimeoutContext.set(30000);
// Child operations automatically use this timeout unless overridden
const { port, operation } = yield* useChannelResponse(); // uses 30s timeout from context
Use Case
In @effectionx/worker, the channel primitives need timeout support. Currently we throw a generic error string:
if (result.timeout) {
throw new Error(`Channel response timed out after ${options.timeout}ms`);
}
With TimeoutError, callers of the worker API could catch and handle timeouts specifically, and with context-based configuration, timeout policies could be set at the application level.
Related
- Used in
@effectionx/workerchannel primitives for request timeout - See
worker/channel.ts-useChannelResponsewith timeout option
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the @effectionx/timebox API and the worker/channel.ts useChannelResponse path mentioned in the issue. Review how timeout results and errors currently flow, then clarify whether the deliverable includes TimeoutError, timeboxOrThrow, context-based defaults, or all three. Done should allow worker callers to handle timeouts specifically and support the agreed timeout configuration behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100