technical

Large uploads and downloads: timeouts, 408 / 400 / 502, and the agent spool

151 views

The Ngris edge paces every HTTP response and every request body between the public client and your agent, one request at a time. A big download to a slow client and a big upload to a slow service both finish, and one slow client doesn't hold up other requests.

Downloads to slow clients

  • The agent sends a response only as fast as its client takes it. A large download to a slow client completes; before, a response more than 32 MiB ahead of its client was reset.
  • A response ends only when no bytes reach its client for 60 seconds, or when its client takes less than 64 KiB in 60 seconds while data is waiting for it. A slow stream the client keeps up with, such as server-sent events, is never cut. Before, a response had 60 seconds in total.
  • Your service has 60 seconds, after the edge has passed it the whole request, to start its response.
  • If an account has a lot of response data waiting at the edge for slow clients, new requests to its endpoints get 503 with Retry-After: 1 until some of it reaches its clients.

Uploads to slow services

The edge reads a request body from the client only as fast as your agent passes it to your service, so a large upload to a slow service completes. The edge answers Expect: 100-continue itself. Before your service has started its response, a failed upload gets one of these statuses from the edge:

  • 408 Request Timeout — the client sent its body slower than 64 KiB per minute (time the edge held the upload back for your service doesn't count), or sent nothing for 60 seconds in the middle of the body.
  • 400 Bad Request — the body is shorter than its Content-Length, or broke off.
  • 502 Bad Gateway — the agent gave no upload credit for 2 minutes: your service stopped reading the body.

Once your service has started answering, a failed upload cuts the response off instead.

The agent spool

When a client reads a response slower than your service writes it, the agent keeps reading your service into a spool — memory first, then a temporary file — and sends from it as the client catches up, so your service is done with the response as soon as it has written it.

  • Where: ~/.cache/ngris/spool on Linux ($XDG_CACHE_HOME/ngris/spool when set), ~/Library/Caches/ngris/spool on macOS, %LocalAppData%\ngris\spool on Windows. Without a user cache directory the agent uses ngris-agent-spool in the temp directory; if the directory isn't the agent's own (a real directory; on Linux and macOS mode 0700, owned by the agent's user), a new private directory in the temp directory; failing that, memory only. The agent logs the directory it picked when it starts.
  • How big: each response uses up to 1 MiB of memory, then a file of up to 1 GiB. All responses of one agent together use at most 64 MiB of memory and 2 GiB of disk, and one client IP (for IPv6, its /64) at most an eighth of each. On tmpfs or ramfs the spool files count against the memory budget.
  • Files: on Linux and macOS a spool file is deleted as soon as it is created, so the directory looks empty while disk space is in use; nothing is left after the agent exits.
  • When it is full: the agent stops reading your service for that response until its client catches up. At most 25 responses per agent wait like this, and at most 3 per client IP; past that the response fails and its client sees the connection reset.

See also Large transfers & timeouts and Files on disk in the docs.

Ask an AI to summarise this page