Is it possible to configure a max execution on the server, for all GraphQl requests?

Let’s imagine that my GraphQl Apollo server is running on Heroku.

I would like to enforce that NO queries/mutations should take longer than 10 seconds.

Is that possible to configure somehow?

These might be useful for you.

I have seen articles online of enforcing a max query time, but I have never needed it; instead of setting a hard max, I typically limit the underlying values that would cause a query to exceed a certain time.

This keeps queries from being hellish, but also allows for queries that take 10.1 seconds. Rather than forcing a query to fail mid-execution, I try to detect and limit queries that would take too long.

That’s also a nice approach. But Heroku enforces it’s clients to deliver a byte before 30 seconds. Otherwise, it will throw an error.

This error is HTML, and because the appollo client assumes it’s JSON ==> we get a JSON.parse error without any help what so ever to give us any hint’s about the actual error (heroku returns some HTML when no byte was delivered).

If you’re using the express variant of apollo server, you should be able to use an express middleware to accomplish this.

Not sure how that would affect subscriptions, if at all.

1 Like

Yes - I ended up doing something like that (using sveltekit, but did it in the hooks file with a promise.race)

@alexb You mentioned you used promise.race, could you help with an example.
I tried both:
1st: Race the timer and request lifecycle stages promises inside requestDidStart
2nd method: Race the timer and request lifecycle requestDidStart.

a skeleton code example how it worked for you would be helpful

Are you using sveltekit?

@alexb I do not use sveltekit. It is a mircroservice that uses ApolloServer
I am building it as a plugin to ApolloServer to timeout any GrapgQL request that takes longer than timer.

Ok - then I don’t think my solution will be that applicable. But here is my approach

const promise1 = new Promise((resolve, reject) => {
    // Your operation
});

const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('Operation timed out after 10 seconds')), 10000);
});

Promise.race([promise1, timeoutPromise])
    .then(result => {
        console.log('Operation completed:', result);
    })
    .catch(error => {
        console.error(error.message);
    });

Explanation:

  1. promise1 is your operation’s Promise.
  2. timeoutPromise is a Promise that will reject with an error message after 10 seconds (10,000 milliseconds).
  3. Promise.race is called with an array containing promise1 and timeoutPromise. This will result in the Promise that settles first (either resolves or rejects) to be the outcome of Promise.race.
  4. If promise1 completes (either resolves or rejects) before 10 seconds, Promise.race will resolve or reject accordingly.
  5. If promise1 does not complete within 10 seconds, timeoutPromise will reject, causing Promise.race to reject with the error message 'Operation timed out after 10 seconds'.
1 Like

Thanks @alexb ! I tried this method and seems like since promise1 starts first, it is unable to cancel it during execution, even though the result is the timeoutpromise ‘Operation timed out after 10 seconds’, the other promise still executes and is not interuptted.

Correct, you need a different solution to cancel a promise (and any underlying compute), but that was not my goal.

I was simply looking for a solution, so the client would never wait more than 10 seconds, and Promise.race solves that