Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save drewwiens/41bda35616817849b7ac683fc05a03fc to your computer and use it in GitHub Desktop.
Save drewwiens/41bda35616817849b7ac683fc05a03fc to your computer and use it in GitHub Desktop.
Work around Azure App Gateway timeout by returning a response as a stream that sends newline character periodically and then the response JSON. The response body to the client is a bunch of newlines followed by the JSON, which is still valid JSON. Only use if you for some reason can't get the gateway timeout limit increased.
import { finalize, firstValueFrom, timeout } from 'rxjs';
const KEEP_ALIVE_INTERVAL = 3 * 1000;
const KEEP_ALIVE_TIMEOUT = 2 * 60 * 1000;
export interface ErrorInHttpResponse {
errorMsg: string;
status: number;
name?: string;
}
// app is the ExpressJS app object. You have to create it elsewhere.
app.post('my-endpoint', (_req, res) => {
res.writeHead(200);
// Send something periodically to prevent Azure App Gateway from terminating
// the request with 504 Gateway Time-out after 20 seconds. Extra whitespace
// before JSON doesn't change the parsed result, and newline was chosen over
// space because it is printed immediately by cURL when testing. This uses
// chunked transfer encoding which is built into NodeJS and browsers.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
// https://nodejs.org/api/http.html#responsewritechunk-encoding-callback
const handle = setInterval(() => res.write('\n'), KEEP_ALIVE_INTERVAL);
let result: unknown[] | ErrorInHttpResponse;
try {
result = await firstValueFrom(
someSlowObservable$.pipe(
timeout(KEEP_ALIVE_TIMEOUT),
finalize(() => clearInterval(handle)),
),
);
} catch (e) {
// Cannot change the HTTP response code since the stream already started
// as 200 OK, so put any error inside the response body:
if (e instanceof Error) {
result = { errorMsg: e.message, status: 500, name: e.name };
} else {
result = { errorMsg: String(e), status: 500 };
}
}
res.write(JSON.stringify(result));
res.end();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment