dot-lookup: fix hanging FMCSA fetch with AbortController (not AbortSignal.timeout)
AbortSignal.timeout() requires Node 17.3+. The API container likely runs an older Node version, so timeouts never fired -> fetch hung forever when FMCSA API is down -> nginx proxy timeout -> 'Failed to fetch' in the browser. Fix: use AbortController + manual setTimeout() which works on all Node versions. All 3 external fetch points (fmcsaFetch x2, SOS x2) now actually abort at 5s. Also: guard final res.json() with !res.headersSent so the 12s deadline fallback and the normal response path can't double-send. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cebc432af8
commit
13492af732
1 changed files with 8 additions and 3 deletions
|
|
@ -20,15 +20,19 @@ const FMCSA_BASE = "https://mobile.fmcsa.dot.gov/qc/services/carriers";
|
|||
|
||||
async function fmcsaFetch(path: string): Promise<any> {
|
||||
if (!FMCSA_API_KEY) return null;
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), 5000);
|
||||
try {
|
||||
const url = `${FMCSA_BASE}/${path}${path.includes("?") ? "&" : "?"}webKey=${FMCSA_API_KEY}`;
|
||||
const resp = await fetch(url, {
|
||||
signal: AbortSignal.timeout(5000),
|
||||
signal: controller.signal,
|
||||
headers: { "Accept": "application/json" },
|
||||
});
|
||||
clearTimeout(timer);
|
||||
if (!resp.ok) return null;
|
||||
return await resp.json();
|
||||
} catch {
|
||||
clearTimeout(timer);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -515,7 +519,7 @@ router.get("/api/v1/dot/lookup", async (req, res) => {
|
|||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ entity_name: name, state_code: state }),
|
||||
signal: AbortSignal.timeout(5000),
|
||||
signal: (() => { const c = new AbortController(); setTimeout(() => c.abort(), 5000); return c.signal; })(),
|
||||
});
|
||||
if (sosResp.ok) {
|
||||
sosStatus = (await sosResp.json()) as { found?: boolean; status?: string; error?: string };
|
||||
|
|
@ -593,6 +597,7 @@ router.get("/api/v1/dot/lookup", async (req, res) => {
|
|||
const redCount = checks.filter(c => c.status === "red").length;
|
||||
const yellowCount = checks.filter(c => c.status === "yellow").length;
|
||||
|
||||
if (res.headersSent) return; // deadline already responded
|
||||
res.json({
|
||||
dot_number: rawDot,
|
||||
legal_name: name,
|
||||
|
|
@ -722,7 +727,7 @@ router.post("/api/v1/dot/name-check", async (req, res) => {
|
|||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ entity_name: name, state_code: stateCode }),
|
||||
signal: AbortSignal.timeout(5000),
|
||||
signal: (() => { const c = new AbortController(); setTimeout(() => c.abort(), 5000); return c.signal; })(),
|
||||
}).then(r => r.json())
|
||||
: Promise.resolve({ skipped: true }),
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue