timeoutInterceptor function
Builds an Interceptor that applies timeout to every call.
The interceptor composes with any deadline already carried by the parent
AbortSignal: if the parent's deadline is tighter than now + timeout,
the parent wins and no wrapping happens. Otherwise a TimeoutSignal is
installed on a copy of the request.
Composition order per RFC 0002: timeout sits outside retry, so the deadline covers all retry attempts, not each individual attempt.
Implementation
Interceptor timeoutInterceptor(Duration timeout) {
if (timeout <= Duration.zero) {
throw ArgumentError.value(
timeout,
'timeout',
'must be a positive duration',
);
}
return <I extends Object, O extends Object>(AnyFn<I, O> next) {
return (Request<I, O> req) {
final parentDeadline = req.signal.deadline;
final candidate = DateTime.now().add(timeout);
if (parentDeadline != null && !candidate.isBefore(parentDeadline)) {
return next(req);
}
final signal = TimeoutSignal(timeout, parent: req.signal);
return next(_withSignal(req, signal));
};
};
}