fix(wizard): retry createDraft on 500/502/503/504 + human error message
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled

POST /api/ea2/flow currently returns 500 after 19s on demo upstream.
Retry once with backoff, then surface a clear 'EA2 backend temporarily
unable to create new processes' message naming the status. The user
gets actionable info instead of a raw 500.
This commit is contained in:
canvas-bot
2026-06-15 19:42:32 +04:00
parent 3a72b74371
commit 5abb3595fc
3 changed files with 204 additions and 10 deletions
+24 -10
View File
@@ -67,17 +67,31 @@ function authHeaders(): Record<string, string> {
export const wizardApi = {
async createDraft(payload: CreateDraftPayload, signal?: AbortSignal) {
const res = await fetch(`${api.config.baseUrl}/api/ea2/flow`, {
method: "POST",
headers: authHeaders(),
body: JSON.stringify({ kind: "definition", status: "draft", ...payload }),
signal,
});
if (!res.ok) {
const detail = await res.text().catch(() => "");
throw new Error(`createDraft ${res.status}: ${detail.slice(0, 200)}`);
const body = JSON.stringify({ kind: "definition", status: "draft", ...payload });
const transient = new Set([500, 502, 503, 504]);
let lastDetail = "";
let lastStatus = 0;
for (let attempt = 0; attempt < 2; attempt++) {
try {
const res = await fetch(`${api.config.baseUrl}/api/ea2/flow`, {
method: "POST",
headers: authHeaders(),
body,
signal,
});
if (res.ok) return await res.json() as { _key: string; name: string };
lastStatus = res.status;
lastDetail = await res.text().catch(() => "");
if (!transient.has(res.status)) break;
} catch (e) {
lastDetail = (e as Error).message;
}
await new Promise((r) => setTimeout(r, 600 * (attempt + 1)));
}
return res.json() as Promise<{ _key: string; name: string }>;
if (transient.has(lastStatus)) {
throw new Error(`The EA2 backend is temporarily unable to create new processes (status ${lastStatus}). Try again in a moment, or report this if it keeps happening.`);
}
throw new Error(`createDraft ${lastStatus}: ${lastDetail.slice(0, 200)}`);
},
async updateDraftConfig(key: string, patch: Record<string, any>, signal?: AbortSignal) {