Files
ttstd-infinite-canvas/backend/internal/app/task_worker_test.go
AetherNo2332 04d8b85eec fix(app): 任务租约 - 续租不再被自己的执行时限打断 (#567)
Original-Commit: 2b796c403f0c99f3b607b53650b42078964ea753
fix(app): 任务租约 - 续租不再被自己的执行时限打断

续租 context 原来派生自任务执行时限(context.WithTimeout(ctx, 5s)):执行时限一到,
续租请求立刻被取消,失败后被误判成"租约失效、等待其他 worker 恢复",任务停在 running,
租约过期后又被别的 worker 重跑(实测一次上游调用被重跑成三次)。

- taskLeaseRenewContext:用 context.WithoutCancel(parent) + 5s,只继承值、不继承取消与时限;
- 收尾处若我方执行时限已到点,不再直接返回租约错误,而是继续走失败收尾(真丢失时行为不变)。

新增用例在旧写法下失败、修复后通过。
2026-09-21 09:37:20 +08:00

42 lines
1.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}
}