feat: add river-backed async task queue
This commit is contained in:
+37
-2
@@ -521,6 +521,7 @@ export async function createChatTask(
|
||||
): Promise<{ task: GatewayTask; next: Record<string, string> }> {
|
||||
return request<{ task: GatewayTask; next: Record<string, string> }>('/api/v1/chat/completions', {
|
||||
body: input,
|
||||
headers: { 'X-Async': 'true' },
|
||||
method: 'POST',
|
||||
token,
|
||||
});
|
||||
@@ -598,6 +599,7 @@ export async function createImageGenerationTask(
|
||||
): Promise<{ task: GatewayTask; next: Record<string, string> }> {
|
||||
return request<{ task: GatewayTask; next: Record<string, string> }>('/api/v1/images/generations', {
|
||||
body: input,
|
||||
headers: { 'X-Async': 'true' },
|
||||
method: 'POST',
|
||||
token,
|
||||
});
|
||||
@@ -609,6 +611,7 @@ export async function createImageEditTask(
|
||||
): Promise<{ task: GatewayTask; next: Record<string, string> }> {
|
||||
return request<{ task: GatewayTask; next: Record<string, string> }>('/api/v1/images/edits', {
|
||||
body: input,
|
||||
headers: { 'X-Async': 'true' },
|
||||
method: 'POST',
|
||||
token,
|
||||
});
|
||||
@@ -636,6 +639,7 @@ export async function createVideoGenerationTask(
|
||||
): Promise<{ task: GatewayTask; next: Record<string, string> }> {
|
||||
return request<{ task: GatewayTask; next: Record<string, string> }>('/api/v1/videos/generations', {
|
||||
body: input,
|
||||
headers: { 'X-Async': 'true' },
|
||||
method: 'POST',
|
||||
token,
|
||||
});
|
||||
@@ -656,6 +660,33 @@ export async function getTask(token: string, taskId: string): Promise<GatewayTas
|
||||
return request<GatewayTask>(`/api/workspace/tasks/${taskId}`, { token });
|
||||
}
|
||||
|
||||
export async function pollTaskUntilSettled(
|
||||
token: string,
|
||||
task: GatewayTask,
|
||||
options: { intervalMs?: number; maxAttempts?: number | null; onUpdate?: (task: GatewayTask) => void } = {},
|
||||
): Promise<GatewayTask> {
|
||||
let detail = task;
|
||||
const intervalMs = options.intervalMs ?? 1200;
|
||||
const maxAttempts = options.maxAttempts ?? Number.POSITIVE_INFINITY;
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
||||
if (!taskIsPending(detail.status)) return detail;
|
||||
try {
|
||||
detail = await getTask(token, detail.id);
|
||||
options.onUpdate?.(detail);
|
||||
if (!taskIsPending(detail.status)) return detail;
|
||||
} catch {
|
||||
// Backend restarts or short network gaps should not turn a durable task into a failed UI run.
|
||||
// Only an explicit terminal task status from the task detail endpoint settles the run.
|
||||
}
|
||||
await delay(intervalMs);
|
||||
}
|
||||
return detail;
|
||||
}
|
||||
|
||||
export function taskIsPending(status: string) {
|
||||
return status === 'queued' || status === 'running' || status === 'submitting';
|
||||
}
|
||||
|
||||
export async function listTasks(token: string, query: WorkspaceTaskQuery): Promise<ListResponse<GatewayTask>> {
|
||||
const search = new URLSearchParams({
|
||||
page: String(query.page),
|
||||
@@ -707,9 +738,9 @@ export async function getNetworkProxyConfig(token: string): Promise<GatewayNetwo
|
||||
|
||||
async function request<T>(
|
||||
path: string,
|
||||
options: { token?: string; auth?: boolean; method?: string; body?: unknown } = {},
|
||||
options: { token?: string; auth?: boolean; method?: string; body?: unknown; headers?: Record<string, string> } = {},
|
||||
): Promise<T> {
|
||||
const headers: Record<string, string> = {};
|
||||
const headers: Record<string, string> = { ...(options.headers ?? {}) };
|
||||
if (options.auth !== false && options.token) {
|
||||
headers.Authorization = `Bearer ${options.token}`;
|
||||
}
|
||||
@@ -731,6 +762,10 @@ async function request<T>(
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
|
||||
function delay(ms: number) {
|
||||
return new Promise((resolve) => window.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function parseErrorMessage(body: string) {
|
||||
return formatGatewayErrorDetails(parseErrorDetails(body));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user