Harden the webhook forwarder's error handling
Node · Node · intermediate · modification
Hardens forwardEvent's error handling: sets an explicit JSON content-type, inspects the response status manually via validateStatus, and rejects non-2xx responses with a typed DeliveryError that carries the status code for the retry scheduler. Happy-path and non-2xx tests pass.
forwardEvent runs inside the event-delivery worker; it POSTs to subscriber-controlled URLs that occasionally accept the connection and then stall without replying.
Requirements
- forwardEvent(subscriberUrl, event) POSTs the event to the subscriber's configured webhook URL and resolves with the HTTP status code.
- Subscriber URLs are customer-controlled third-party endpoints that can be slow or hang without ever responding.
- The outbound POST must be time-bounded: if the subscriber stops responding, the call must abort rather than wait indefinitely.
- A non-2xx response must reject with an error that carries the status code, so the delivery worker can schedule a retry.
- Out of scope for this change: the subscriber URL is already validated against an allowlist upstream (SSRF-safe), and the platform's shared outbound layer enforces response-size and decompression caps — the only concern in this diff is bounding the request's time.
Files touched
- src/webhooks/forwarder.js
--- src/webhooks/forwarder.js
const axios = require('axios');
+
+class DeliveryError extends Error {
+ constructor(status) {
+ super(`subscriber responded ${status}`);
+ this.name = 'DeliveryError';
+ this.status = status;
+ }
+}
// Deliver a received event to the subscriber's configured webhook URL.
async function forwardEvent(subscriberUrl, event) {
- const res = await axios.post(subscriberUrl, event);
+ const res = await axios.post(subscriberUrl, event, {
+ headers: { 'Content-Type': 'application/json' },
+ validateStatus: () => true,
+ });
+ if (res.status < 200 || res.status >= 300) {
+ throw new DeliveryError(res.status);
+ }
return res.status;
}
-module.exports = { forwardEvent };
+module.exports = { forwardEvent, DeliveryError };