feat: add durable relative task delays and outage recovery regression
This commit is contained in:
66
sdk/go/task_delay_integration_test.go
Normal file
66
sdk/go/task_delay_integration_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package orbit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestIntegrationWorkerRuntimeDelayedSubmission(t *testing.T) {
|
||||
api, queue, _ := integrationWorkerClient(t)
|
||||
ctx, stop := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer stop()
|
||||
name := "delay." + workerTestID(t)
|
||||
key := workerTestID(t)
|
||||
in := SubmitTaskRequest{QueueID: queue, Handler: name, HandlerVersion: "v1", PayloadVersion: "v1", Payload: json.RawMessage(`{"n":9007199254740993}`), DelayMS: 1500, TaskTimeoutMS: 15000, Retry: RetryPolicy{MaxAttempts: 1, AttemptTimeoutMS: 5000}}
|
||||
delayed, err := api.SubmitTask(ctx, key, in)
|
||||
if err != nil || !delayed.Task.AvailableAt.Equal(delayed.Task.CreatedAt.Add(1500*time.Millisecond)) {
|
||||
t.Fatal("relative delay not persisted", err)
|
||||
}
|
||||
at := delayed.Task.CreatedAt.Add(3 * time.Second)
|
||||
absoluteInput := in
|
||||
absoluteInput.DelayMS, absoluteInput.AvailableAt = 0, &at
|
||||
absolute, err := api.SubmitTask(ctx, workerTestID(t), absoluteInput)
|
||||
if err != nil || !absolute.Task.AvailableAt.Equal(at) {
|
||||
t.Fatal("absolute release time changed", err)
|
||||
}
|
||||
r, err := NewWorkerRegistration(queue, 1, []WorkerCapability{{Handler: name, HandlerVersion: "v1", PayloadVersion: "v1"}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w, err := api.DialWorker(ctx, r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer w.Close()
|
||||
if _, err := w.Capacity(ctx, workerTestID(t), WorkerCapacity{Sequence: 1, Capacity: 1}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []Task{delayed.Task, absolute.Task} {
|
||||
a, err := w.NextAssignment(ctx)
|
||||
if err != nil || a.Task.ID != want.ID || a.ServerTime.Before(want.AvailableAt) || a.Epoch != 1 {
|
||||
t.Fatal("task dispatched before its persisted release time", err)
|
||||
}
|
||||
if _, err := w.Start(ctx, workerTestID(t), a.Attempt()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := w.Finish(ctx, workerTestID(t), WorkerFinish{Ref: a.Attempt(), Outcome: WorkerSucceeded, Result: a.Task.Payload}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
history, err := api.GetTaskAttempt(ctx, want.ID, a.AttemptID)
|
||||
if err != nil || history.CreatedAt.Before(want.AvailableAt) || history.AuthorizedAt == nil || history.AuthorizedAt.Before(want.AvailableAt) {
|
||||
t.Fatal("persisted history allowed an early start", err)
|
||||
}
|
||||
}
|
||||
// 原等待时长已经经过,原键重报仍返回首次回执,不能建立新的计时或任务。
|
||||
dupe, err := api.SubmitTask(ctx, key, in)
|
||||
if err != nil || !dupe.Deduplicated || dupe.Task.ID != delayed.Task.ID || !dupe.Task.AvailableAt.Equal(delayed.Task.AvailableAt) || !dupe.Task.DeadlineAt.Equal(delayed.Task.DeadlineAt) {
|
||||
t.Fatal("late replay reset original delay", err)
|
||||
}
|
||||
current, err := api.GetTask(ctx, delayed.Task.ID)
|
||||
if err != nil || current.State != TaskSucceeded || current.AttemptCount != 1 {
|
||||
t.Fatal("late replay reopened a completed task", err)
|
||||
}
|
||||
t.Log("relative and absolute release times obey database history; replay after elapsed delay returns original receipt without reopening")
|
||||
}
|
||||
Reference in New Issue
Block a user