feat: add durable relative task delays and outage recovery regression
This commit is contained in:
@@ -64,6 +64,9 @@ func NormalizeSubmit(in SubmitInput) (SubmitInput, error) {
|
||||
if in.TaskTimeoutMS > 30*24*60*60*1000 {
|
||||
return in, fault.Invalid("task_timeout_ms exceeds 30 days")
|
||||
}
|
||||
if in.DelayMS >= in.TaskTimeoutMS || (in.DelayMS != 0 && in.AvailableAt != nil) {
|
||||
return in, fault.Invalid("delay_ms must be less than task_timeout_ms and cannot be combined with available_at")
|
||||
}
|
||||
if in.RecoverySafety == "" {
|
||||
in.RecoverySafety = pulse.RecoveryReconcileOnly
|
||||
}
|
||||
|
||||
@@ -24,7 +24,14 @@ func TestSubmitNormalizationAndBounds(t *testing.T) {
|
||||
"unbounded attempts": func(v *SubmitInput) { v.Retry.MaxAttempts = 101 },
|
||||
"unknown recovery policy": func(v *SubmitInput) { v.RecoverySafety = "UNKNOWN" },
|
||||
"excess timeout": func(v *SubmitInput) { v.TaskTimeoutMS = 30*86400000 + 1 },
|
||||
"sub-microsecond time": func(v *SubmitInput) { now := time.Date(2026, 1, 1, 0, 0, 0, 1, time.UTC); v.AvailableAt = &now },
|
||||
"delay equals deadline": func(v *SubmitInput) { v.DelayMS = 86400000 },
|
||||
"delay overflow": func(v *SubmitInput) { v.DelayMS = ^uint64(0) },
|
||||
"both timing modes": func(v *SubmitInput) {
|
||||
now := time.Now().UTC().Truncate(time.Microsecond)
|
||||
v.AvailableAt = &now
|
||||
v.DelayMS = 1
|
||||
},
|
||||
"sub-microsecond time": func(v *SubmitInput) { now := time.Date(2026, 1, 1, 0, 0, 0, 1, time.UTC); v.AvailableAt = &now },
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
in := base
|
||||
@@ -34,6 +41,10 @@ func TestSubmitNormalizationAndBounds(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
base.DelayMS = 86400000 - 1
|
||||
if out, err := NormalizeSubmit(base); err != nil || out.DelayMS != base.DelayMS || out.AvailableAt != nil {
|
||||
t.Fatal("relative delay was resolved before database acceptance", err)
|
||||
}
|
||||
for _, key := range []string{"", strings.Repeat("a", 129), "with space", "带中文", "line\n"} {
|
||||
if ValidateKey(key) == nil {
|
||||
t.Fatal("accepted invalid key")
|
||||
|
||||
@@ -29,7 +29,9 @@ type SubmitInput struct {
|
||||
ConcurrencyKey string `json:"concurrency_key,omitempty"`
|
||||
// Priority 冻结优先级,0至9,每级30秒排序优势,不改变最早执行时间。
|
||||
Priority int16 `json:"priority,omitempty"`
|
||||
// AvailableAt 最早执行时间;为空表示受理后即可进入派发范围。
|
||||
// DelayMS 相对首次受理数据库时间的等待毫秒数;零为不延迟,非零不能与 AvailableAt 同用。
|
||||
DelayMS uint64 `json:"delay_ms,omitempty"`
|
||||
// AvailableAt 最早执行时间;为空且 DelayMS 为零表示受理后即可进入派发范围。
|
||||
AvailableAt *time.Time `json:"available_at,omitempty"`
|
||||
// StartDeadlineAt 最晚开始时间;为空表示使用任务总截止时间。
|
||||
StartDeadlineAt *time.Time `json:"start_deadline_at,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user