This page is a placeholder. All examples on this page are currently AI-generated and are not correct. This documentation will be completed in the future with accurate, tested examples.
Timeout
Add timeouts to promises and async operations. Essential for preventing hung requests, managing long-running operations, and implementing cancellation in Ethereum applications.
Overview
Timeout utilities provide:
- Promise timeouts: Race promises against time limit
- Cancellation: AbortSignal support
- Function wrapping: Create timeout-wrapped versions
- Deferred promises: Manual promise control
- Retry integration: Timeout + retry patterns
Basic Usage
Simple Timeout
Wrap a promise with timeout:
import { withTimeout } from '@tevm/voltaire/utils';
const result = await withTimeout(
provider.eth_getBlockByNumber('latest'),
{ ms: 5000 }
);
Custom Timeout Message
const balance = await withTimeout(
provider.eth_getBalance(address),
{
ms: 10000,
message: 'Balance fetch timed out after 10s'
}
);
Timeout Options
TimeoutOptions
interface TimeoutOptions {
ms: number; // Timeout duration in milliseconds
message?: string; // Error message (default: "Operation timed out")
signal?: AbortSignal; // Optional AbortController signal
}
Timeout Functions
withTimeout
Add timeout to any promise:
try {
const data = await withTimeout(
fetchData(),
{ ms: 30000 }
);
} catch (error) {
if (error instanceof TimeoutError) {
console.log('Operation timed out');
}
}
wrapWithTimeout
Create timeout-wrapped functions:
import { wrapWithTimeout } from '@tevm/voltaire/utils';
const getBalanceWithTimeout = wrapWithTimeout(
(address: string) => provider.eth_getBalance(address),
5000,
'Balance fetch timeout'
);
const balance = await getBalanceWithTimeout('0x123...');
sleep
Async delay with optional cancellation:
import { sleep } from '@tevm/voltaire/utils';
// Simple delay
await sleep(1000);
// Cancellable delay
const controller = new AbortController();
const sleepPromise = sleep(5000, controller.signal);
// Cancel after 1 second
setTimeout(() => controller.abort(), 1000);
try {
await sleepPromise;
} catch (error) {
console.log('Sleep cancelled');
}
createDeferred
Manual promise control:
import { createDeferred } from '@tevm/voltaire/utils';
const { promise, resolve, reject } = createDeferred<number>();
// Resolve from event handler
provider.on('block', (blockNumber) => {
if (blockNumber > 1000000) {
resolve(blockNumber);
}
});
// Reject on timeout
setTimeout(() => reject(new Error('Timeout')), 30000);
const result = await promise;
executeWithTimeout
Timeout with built-in retry:
import { executeWithTimeout } from '@tevm/voltaire/utils';
const block = await executeWithTimeout(
() => provider.eth_getBlockByNumber('latest'),
5000, // 5s timeout per attempt
3 // Retry up to 3 times
);
Cancellation with AbortSignal
Basic Cancellation
const controller = new AbortController();
const dataPromise = withTimeout(
fetch('https://api.example.com/data'),
{
ms: 30000,
signal: controller.signal
}
);
// Cancel operation
controller.abort();
try {
await dataPromise;
} catch (error) {
if (error.message === 'Operation aborted') {
console.log('User cancelled operation');
}
}
Multiple Operations
Share abort controller across operations:
const controller = new AbortController();
const operations = [
withTimeout(
provider.eth_getBalance(address1),
{ ms: 10000, signal: controller.signal }
),
withTimeout(
provider.eth_getBalance(address2),
{ ms: 10000, signal: controller.signal }
),
withTimeout(
provider.eth_getBalance(address3),
{ ms: 10000, signal: controller.signal }
)
];
// Cancel all operations
if (userCancelled) {
controller.abort();
}
const results = await Promise.allSettled(operations);
Real-World Examples
RPC Call with Timeout
Prevent hung RPC calls:
async function safeRpcCall<T>(
fn: () => Promise<T>,
timeoutMs: number = 10000
): Promise<T> {
return withTimeout(fn(), {
ms: timeoutMs,
message: `RPC call timeout after ${timeoutMs}ms`
});
}
const blockNumber = await safeRpcCall(
() => provider.eth_blockNumber(),
5000
);
Transaction Submission
Timeout transaction submission:
const txHash = await withTimeout(
provider.eth_sendRawTransaction(signedTx),
{
ms: 30000,
message: 'Transaction submission timeout'
}
);
Parallel Operations with Global Timeout
Timeout entire batch:
const results = await withTimeout(
Promise.all([
provider.eth_getBalance(address1),
provider.eth_getBalance(address2),
provider.eth_getBalance(address3)
]),
{
ms: 15000,
message: 'Batch operation timeout'
}
);
Race Against Multiple Providers
Use fastest provider:
const providers = [
new HttpProvider('https://eth.llamarpc.com'),
new HttpProvider('https://rpc.ankr.com/eth'),
new HttpProvider('https://cloudflare-eth.com')
];
const blockNumber = await Promise.race(
providers.map(p =>
withTimeout(
p.eth_blockNumber(),
{ ms: 5000 }
)
)
);
User-Initiated Cancellation
Cancel long-running operation:
const controller = new AbortController();
// UI cancel button
cancelButton.onclick = () => controller.abort();
try {
const logs = await withTimeout(
provider.eth_getLogs({
fromBlock: '0x0',
toBlock: 'latest'
}),
{
ms: 60000,
signal: controller.signal,
message: 'Log fetch timeout'
}
);
} catch (error) {
if (error.message === 'Operation aborted') {
console.log('User cancelled');
} else if (error instanceof TimeoutError) {
console.log('Operation timed out');
}
}
Combining with Other Utils
Timeout + Retry
Retry with timeout per attempt:
import { retryWithBackoff, withTimeout } from '@tevm/voltaire/utils';
const data = await retryWithBackoff(
() => withTimeout(
provider.eth_call({ to, data }),
{ ms: 5000 }
),
{
maxRetries: 3,
shouldRetry: (error) => {
// Don't retry on timeout
return !(error instanceof TimeoutError);
}
}
);
Timeout + Polling
Add timeout to polling:
import { poll, withTimeout } from '@tevm/voltaire/utils';
const receipt = await withTimeout(
poll(
() => provider.eth_getTransactionReceipt(txHash),
{ interval: 1000 }
),
{
ms: 120000,
message: 'Transaction confirmation timeout after 2 minutes'
}
);
Timeout + Rate Limiting
Timeout rate-limited operations:
import { RateLimiter, withTimeout } from '@tevm/voltaire/utils';
const limiter = new RateLimiter({
maxRequests: 10,
interval: 1000
});
const result = await withTimeout(
limiter.execute(() => provider.eth_blockNumber()),
{
ms: 15000,
message: 'Rate-limited operation timeout'
}
);
Error Handling
TimeoutError
Catch timeout-specific errors:
import { withTimeout, TimeoutError } from '@tevm/voltaire/utils';
try {
await withTimeout(
longRunningOperation(),
{ ms: 30000 }
);
} catch (error) {
if (error instanceof TimeoutError) {
console.log('Operation timed out');
// Retry or fallback
} else {
// Other error
throw error;
}
}
Cleanup on Timeout
Perform cleanup when timeout occurs:
const controller = new AbortController();
try {
await withTimeout(
fetchWithAbort(url, controller.signal),
{ ms: 10000 }
);
} catch (error) {
if (error instanceof TimeoutError) {
controller.abort(); // Clean up pending request
}
throw error;
}
Best Practices
Choose Appropriate Timeouts
- Fast operations (balance, blockNumber): 5000-10000ms
- Medium operations (calls, receipts): 10000-30000ms
- Slow operations (logs, traces): 30000-60000ms
Always Handle TimeoutError
try {
await withTimeout(operation(), { ms: 10000 });
} catch (error) {
if (error instanceof TimeoutError) {
// Handle timeout specifically
} else {
// Handle other errors
}
}
Use AbortSignal for Cleanup
When operations support AbortSignal, use it for proper cleanup:
const controller = new AbortController();
withTimeout(
fetch(url, { signal: controller.signal }),
{
ms: 10000,
signal: controller.signal
}
);
Per-Operation vs Global Timeout
- Per-operation: Each request has own timeout
- Global: Entire batch has single timeout
// Per-operation: Each has 5s
await Promise.all(
addresses.map(addr =>
withTimeout(
provider.eth_getBalance(addr),
{ ms: 5000 }
)
)
);
// Global: All must complete in 10s total
await withTimeout(
Promise.all(
addresses.map(addr => provider.eth_getBalance(addr))
),
{ ms: 10000 }
);
API Reference
withTimeout
async function withTimeout<T>(
promise: Promise<T>,
options: TimeoutOptions
): Promise<T>
wrapWithTimeout
function wrapWithTimeout<TArgs extends any[], TReturn>(
fn: (...args: TArgs) => Promise<TReturn>,
ms: number,
message?: string
): (...args: TArgs) => Promise<TReturn>
sleep
function sleep(
ms: number,
signal?: AbortSignal
): Promise<void>
createDeferred
function createDeferred<T>(): {
promise: Promise<T>;
resolve: (value: T) => void;
reject: (error: unknown) => void;
}
executeWithTimeout
async function executeWithTimeout<T>(
fn: () => Promise<T>,
timeoutMs: number,
maxRetries?: number
): Promise<T>
TimeoutError
class TimeoutError extends Error {
constructor(message?: string)
}
See Also