Timeouts for RestDataSource methods

On upgrading to @apollo/datasource-rest (4.3.2) from apollo-datasource-rest (3.6.1), I’ve noticed that there no longer seems to be a way to set a timeout on the request for e.g. get().

Is that correct? And if so is there some builtin timeout or is it the responsibility of the caller to implement their own timeout support?

1 Like

The FetcherRequestInit type (one of the types that makes up the “request options” param for, e.g., RESTDataSource.get(...)) contains a signal field. You can set the timeout like this:

const response = this.get('https://example.com', {signal: AbortSignal.timeout(myTimeoutMilliseconds)});

Docs for AbortSignal: AbortSignal.timeout() - Web APIs | MDN

1 Like

Many thanks @AaronT - that did the trick (although there appears to be an issue with typescript and the AbortSignal API that I had to work around in Nodejs 16x).

1 Like

Ah, yes I saw a comment in the source re that:

  // A provided `signal` should be an object created by a class named
  // `AbortSignal` (the constructor name is checked by some implementations like
  // node-fetch and make-fetch-happen!) which follows the DOM AbortSignal API.
  // Notably, it should have `aborted: boolean` and methods `addEventListener`
  // and `removeEventListener`. We do not provide a precise interface for it
  // because we have found that runtime implementations are more consistent than
  // TypeScript definitions; for example, the methods such as addEventListener
  // end up being defined in terms of complex DOM types which vary by
  // implementation.
  //
  // Note that a relatively recent addition to the spec
  // (https://github.com/whatwg/dom/pull/1027) is the concept of an abort
  // reason. None of the polyfill Node AbortController/AbortSignal
  // implementations seems to support this yet (though Node's built-in
  // implementation does as of v18). It is possible that some Fetch
  // implementations might rely on the existence of this new functionality, say
  // by calling signal.throwIfAborted(). If so, you would need to use an
  // AbortSignal that supports this (such as the Node v18 implementation). As of
  // now, it does not appear that node-fetch, make-fetch-happen, or undici rely
  // on throwIfAborted, although undici does look at signal.reason if it is
  // provided.
  //
  // The main motivation for providing this as `any` (rather than, say, an
  // interface where the functions take `any` arguments to avoid linking in DOM)
  // is because if we leave out the newer `reason`/`throwIfAborted` fields, then
  // implementations like undici that use the Node v18 definitions won't
  // typecheck, but if we include those fields, then `AbortSignal`s from
  // `AbortController` polyfill libraries such as `node-abort-controller` won't
  // typecheck because they don't provide those fields. While in a sense that's
  // correct, we don't want to provide an interface for which there are no
  // existing implementations for Node v16 or older! (We may later choose to
  // publish our own polyfill and make this type more exact.)
  signal?: any;