feat: add river-backed async task queue
This commit is contained in:
@@ -21,7 +21,7 @@ import { mermaid } from '@streamdown/mermaid';
|
||||
import type { GatewayApiKey, GatewayTask, PlatformModel } from '@easyai-ai-gateway/contracts';
|
||||
import { Bot, ChevronDown, Image as ImageIcon, MessageSquarePlus, Paperclip, Send, Sparkles, Video } from 'lucide-react';
|
||||
import { Badge, Button, Select, Textarea } from '../components/ui';
|
||||
import { GatewayApiError, createImageGenerationTask, createVideoGenerationTask, getTask, streamChatCompletionText } from '../api';
|
||||
import { GatewayApiError, createImageGenerationTask, createVideoGenerationTask, pollTaskUntilSettled, streamChatCompletionText, taskIsPending } from '../api';
|
||||
import type { PlaygroundMode } from '../types';
|
||||
import {
|
||||
defaultMediaGenerationSettings,
|
||||
@@ -170,14 +170,12 @@ export function PlaygroundPage(props: {
|
||||
resumableRuns.forEach((run) => {
|
||||
if (!run.task?.id) return;
|
||||
resumedTaskIdsRef.current.add(run.task.id);
|
||||
void pollTaskUntilSettled(credential, run.task)
|
||||
void pollTaskUntilSettled(credential, run.task, {
|
||||
onUpdate: (detail) => updateMediaRunFromTask(run.localId, detail),
|
||||
})
|
||||
.then((detail) => {
|
||||
if (!isMountedRef.current) return;
|
||||
setMediaRuns((current) => updateMediaRun(current, run.localId, {
|
||||
error: gatewayTaskErrorText(detail, '任务执行失败'),
|
||||
status: detail.status,
|
||||
task: detail,
|
||||
}));
|
||||
updateMediaRunFromTask(run.localId, detail);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (!isMountedRef.current) return;
|
||||
@@ -249,13 +247,11 @@ export function PlaygroundPage(props: {
|
||||
|
||||
async function pollMediaRunUntilSettled(credential: string, localId: string, task: GatewayTask) {
|
||||
try {
|
||||
const detail = await pollTaskUntilSettled(credential, task);
|
||||
const detail = await pollTaskUntilSettled(credential, task, {
|
||||
onUpdate: (nextTask) => updateMediaRunFromTask(localId, nextTask),
|
||||
});
|
||||
if (!isMountedRef.current) return;
|
||||
setMediaRuns((current) => updateMediaRun(current, localId, {
|
||||
error: gatewayTaskErrorText(detail, '任务执行失败'),
|
||||
status: detail.status,
|
||||
task: detail,
|
||||
}));
|
||||
updateMediaRunFromTask(localId, detail);
|
||||
} catch (err) {
|
||||
if (!isMountedRef.current) return;
|
||||
const errorMessage = err instanceof Error ? err.message : '任务状态同步失败';
|
||||
@@ -263,6 +259,15 @@ export function PlaygroundPage(props: {
|
||||
}
|
||||
}
|
||||
|
||||
function updateMediaRunFromTask(localId: string, task: GatewayTask) {
|
||||
if (!isMountedRef.current) return;
|
||||
setMediaRuns((current) => updateMediaRun(current, localId, {
|
||||
error: taskIsPending(task.status) ? '' : gatewayTaskErrorText(task, '任务执行失败'),
|
||||
status: task.status,
|
||||
task,
|
||||
}));
|
||||
}
|
||||
|
||||
function editMediaRun(run: MediaGenerationRun) {
|
||||
setPrompt(run.prompt);
|
||||
setMediaSettings(run.settings);
|
||||
@@ -1042,20 +1047,6 @@ function updateMediaRun(runs: MediaGenerationRun[], localId: string, patch: Part
|
||||
return runs.map((run) => run.localId === localId ? { ...run, ...patch } : run);
|
||||
}
|
||||
|
||||
async function pollTaskUntilSettled(token: string, task: GatewayTask) {
|
||||
let detail = task;
|
||||
for (let attempt = 0; attempt < 20; attempt += 1) {
|
||||
detail = await getTask(token, detail.id);
|
||||
if (!taskIsPending(detail.status)) return detail;
|
||||
await delay(1200);
|
||||
}
|
||||
return detail;
|
||||
}
|
||||
|
||||
function taskIsPending(status: string) {
|
||||
return status === 'queued' || status === 'running' || status === 'submitting';
|
||||
}
|
||||
|
||||
function readStoredMediaRuns(): MediaGenerationRun[] {
|
||||
if (typeof window === 'undefined') return [];
|
||||
try {
|
||||
@@ -1182,10 +1173,6 @@ function booleanFromUnknown(value: unknown, fallback: boolean) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function delay(ms: number) {
|
||||
return new Promise((resolve) => window.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function newLocalId() {
|
||||
return typeof crypto !== 'undefined' && 'randomUUID' in crypto
|
||||
? crypto.randomUUID()
|
||||
|
||||
Reference in New Issue
Block a user