feat: async task pipeline for media and llm workflows
这个提交包含在:
@@ -53,14 +53,40 @@ export type MediaSession = {
|
||||
};
|
||||
|
||||
const MEDIA_BASE = (import.meta.env.VITE_MEDIA_BASE_URL || "/media").replace(/\/$/, "");
|
||||
const RETRYABLE_STATUS = new Set([502, 503, 504]);
|
||||
|
||||
function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const response = await fetch(`${MEDIA_BASE}${path}`, init);
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.json().catch(() => ({}));
|
||||
throw new Error(errorBody.error || errorBody.message || `Media service error (${response.status})`);
|
||||
let lastError: Error | null = null;
|
||||
|
||||
for (let attempt = 0; attempt < 3; attempt++) {
|
||||
try {
|
||||
const response = await fetch(`${MEDIA_BASE}${path}`, init);
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.json().catch(() => ({}));
|
||||
const error = new Error(errorBody.error || errorBody.message || `Media service error (${response.status})`);
|
||||
if (RETRYABLE_STATUS.has(response.status) && attempt < 2) {
|
||||
lastError = error;
|
||||
await sleep(400 * (attempt + 1));
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return response.json() as Promise<T>;
|
||||
} catch (error) {
|
||||
lastError = error instanceof Error ? error : new Error("Media request failed");
|
||||
if (attempt < 2) {
|
||||
await sleep(400 * (attempt + 1));
|
||||
continue;
|
||||
}
|
||||
throw lastError;
|
||||
}
|
||||
}
|
||||
return response.json() as Promise<T>;
|
||||
|
||||
throw lastError || new Error("Media request failed");
|
||||
}
|
||||
|
||||
export async function createMediaSession(payload: {
|
||||
|
||||
在新工单中引用
屏蔽一个用户