Original-Commit: 2b796c403f0c99f3b607b53650b42078964ea753 fix(app): 任务租约 - 续租不再被自己的执行时限打断 续租 context 原来派生自任务执行时限(context.WithTimeout(ctx, 5s)):执行时限一到, 续租请求立刻被取消,失败后被误判成"租约失效、等待其他 worker 恢复",任务停在 running, 租约过期后又被别的 worker 重跑(实测一次上游调用被重跑成三次)。 - taskLeaseRenewContext:用 context.WithoutCancel(parent) + 5s,只继承值、不继承取消与时限; - 收尾处若我方执行时限已到点,不再直接返回租约错误,而是继续走失败收尾(真丢失时行为不变)。 新增用例在旧写法下失败、修复后通过。
42 lines
1.5 KiB
Go
42 lines
1.5 KiB
Go
package app
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
// 续租必须比"这条任务的执行时限"活得更久:否则父 context 到点时,续租请求会被自己的
|
||
// 执行时限取消,失败后被误判成"租约失效"(任务停在 running,租约过期后被别的 worker 重跑)。
|
||
func TestTaskLeaseRenewContextSurvivesExecutionDeadline(t *testing.T) {
|
||
parent, cancelParent := context.WithTimeout(context.Background(), 20*time.Millisecond)
|
||
defer cancelParent()
|
||
<-parent.Done()
|
||
if parent.Err() == nil {
|
||
t.Fatal("父 context 应当已到点")
|
||
}
|
||
|
||
renew, cancelRenew := taskLeaseRenewContext(parent)
|
||
defer cancelRenew()
|
||
if err := renew.Err(); err != nil {
|
||
t.Fatalf("父 context 到点后,续租 context 不该被取消:%v", err)
|
||
}
|
||
deadline, ok := renew.Deadline()
|
||
if !ok {
|
||
t.Fatal("续租 context 必须保有自己的上限")
|
||
}
|
||
if remaining := time.Until(deadline); remaining <= 0 || remaining > 5*time.Second {
|
||
t.Fatalf("续租上限应当是全新的 5 秒,实际剩余 %v", remaining)
|
||
}
|
||
|
||
// 父 context 之后再取消,也不能把已经建好的续租 context 一起取消(worker 退出时
|
||
// 续租请求最多自己超时,而不是被"任务已结束"顺手打断)。
|
||
parent2, cancelParent2 := context.WithCancel(context.Background())
|
||
renew2, cancelRenew2 := taskLeaseRenewContext(parent2)
|
||
defer cancelRenew2()
|
||
cancelParent2()
|
||
if err := renew2.Err(); err != nil {
|
||
t.Fatalf("父 context 取消不该连带取消续租 context:%v", err)
|
||
}
|
||
}
|