feat: add river-backed async task queue

This commit is contained in:
2026-05-12 10:11:54 +08:00
parent d69aaed444
commit 7e220b7477
30 changed files with 1342 additions and 200 deletions
+58
View File
@@ -329,6 +329,7 @@ func TestVolcesClientVideoSubmitsAndPollsTask(t *testing.T) {
var gotModel string
var gotText string
var gotFirstFrameRole string
var submittedRemoteTaskID string
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotAuth = r.Header.Get("Authorization")
switch r.Method + " " + r.URL.Path {
@@ -385,6 +386,13 @@ func TestVolcesClientVideoSubmitsAndPollsTask(t *testing.T) {
"volcesPollTimeoutSeconds": 1,
},
},
OnRemoteTaskSubmitted: func(remoteTaskID string, payload map[string]any) error {
submittedRemoteTaskID = remoteTaskID
if payload["id"] != "cgt-test" {
t.Fatalf("unexpected submitted payload: %+v", payload)
}
return nil
},
})
if err != nil {
t.Fatalf("run volces video: %v", err)
@@ -392,6 +400,9 @@ func TestVolcesClientVideoSubmitsAndPollsTask(t *testing.T) {
if submitPath != "/contents/generations/tasks" || pollPath != "/contents/generations/tasks/cgt-test" || gotAuth != "Bearer volces-key" {
t.Fatalf("unexpected paths/auth submit=%s poll=%s auth=%s", submitPath, pollPath, gotAuth)
}
if submittedRemoteTaskID != "cgt-test" {
t.Fatalf("remote task submit callback did not receive task id, got %q", submittedRemoteTaskID)
}
if gotModel != "doubao-seedance-2-0-260128" || gotFirstFrameRole != "first_frame" {
t.Fatalf("unexpected submitted model=%s role=%s", gotModel, gotFirstFrameRole)
}
@@ -407,6 +418,53 @@ func TestVolcesClientVideoSubmitsAndPollsTask(t *testing.T) {
}
}
func TestVolcesClientVideoResumePollsExistingTaskID(t *testing.T) {
var submitCalled bool
var pollPath string
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method + " " + r.URL.Path {
case "POST /contents/generations/tasks":
submitCalled = true
t.Fatalf("resume should skip upstream submit when remote task id exists")
case "GET /contents/generations/tasks/cgt-existing":
pollPath = r.URL.Path
_ = json.NewEncoder(w).Encode(map[string]any{
"id": "cgt-existing",
"status": "succeeded",
"created_at": 789,
"content": map[string]any{"video_url": "https://example.com/resumed.mp4"},
})
default:
t.Fatalf("unexpected request %s %s", r.Method, r.URL.Path)
}
}))
defer server.Close()
response, err := (VolcesClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
Kind: "videos.generations",
ModelType: "video_generate",
Model: "豆包Seedance-2.0",
Body: map[string]any{"prompt": "resume polling", "pollIntervalMs": 100, "pollTimeoutSeconds": 1},
RemoteTaskID: "cgt-existing",
Candidate: store.RuntimeModelCandidate{
BaseURL: server.URL,
ModelName: "豆包Seedance-2.0",
Credentials: map[string]any{"apiKey": "volces-key"},
},
})
if err != nil {
t.Fatalf("resume volces video: %v", err)
}
if submitCalled || pollPath != "/contents/generations/tasks/cgt-existing" {
t.Fatalf("resume should poll existing task only, submit=%v poll=%s", submitCalled, pollPath)
}
data, _ := response.Result["data"].([]any)
item, _ := data[0].(map[string]any)
if response.Result["upstream_task_id"] != "cgt-existing" || item["url"] != "https://example.com/resumed.mp4" {
t.Fatalf("unexpected resumed response: %+v", response.Result)
}
}
func extractText(result map[string]any) string {
choices, _ := result["choices"].([]any)
choice, _ := choices[0].(map[string]any)