同平台 retry_same 之前会在首个 attempt 失败时释放任务级 admission 租约,下一次 attempt 继续续租旧租约并进入 upstream_submission_unknown。 现在明确区分 attempt 自有租约与任务级 admission 租约,只在 attempt 结束时释放前者;补充回归测试覆盖同平台重试继续续租 admission 租约。 验证:env -u AI_GATEWAY_TEST_DATABASE_URL go test ./... -count=1;go vet ./...;gofmt;git diff --check。
60 lines
2.5 KiB
Go
60 lines
2.5 KiB
Go
package runner
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
|
|
)
|
|
|
|
func TestLeaseRenewalFatalityDistinguishesTransientDatabaseErrors(t *testing.T) {
|
|
now := time.Now()
|
|
deadline := now.Add(time.Minute)
|
|
transient := errors.New("lock timeout")
|
|
if taskExecutionLeaseRenewalIsFatal(transient, now, deadline) {
|
|
t.Fatal("transient task lease renewal error must be retried before expiry")
|
|
}
|
|
if concurrencyLeaseRenewalIsFatal(transient, now, deadline) {
|
|
t.Fatal("transient concurrency lease renewal error must be retried before expiry")
|
|
}
|
|
if !taskExecutionLeaseRenewalIsFatal(store.ErrTaskExecutionLeaseLost, now, deadline) {
|
|
t.Fatal("confirmed task lease ownership loss must be fatal")
|
|
}
|
|
if !concurrencyLeaseRenewalIsFatal(store.ErrConcurrencyLeaseLost, now, deadline) {
|
|
t.Fatal("confirmed concurrency lease ownership loss must be fatal")
|
|
}
|
|
if !taskExecutionLeaseRenewalIsFatal(transient, deadline, deadline) {
|
|
t.Fatal("task lease renewal error at expiry must be fatal")
|
|
}
|
|
if !concurrencyLeaseRenewalIsFatal(transient, deadline, deadline) {
|
|
t.Fatal("concurrency lease renewal error at expiry must be fatal")
|
|
}
|
|
}
|
|
|
|
func TestBindAttemptConcurrencyLeasesPreservesAdmissionLeaseAcrossRetry(t *testing.T) {
|
|
attemptLease := store.ConcurrencyLease{ID: "attempt-lease", TTL: time.Minute}
|
|
admissionLeases := []store.ConcurrencyLease{
|
|
{ID: "admission-user-group", TTL: 2 * time.Minute},
|
|
{ID: "admission-worker-capacity", TTL: 2 * time.Minute},
|
|
}
|
|
|
|
active, release := bindAttemptConcurrencyLeases([]store.ConcurrencyLease{attemptLease}, admissionLeases)
|
|
if len(active) != 3 || active[0].ID != attemptLease.ID || active[1].ID != admissionLeases[0].ID || active[2].ID != admissionLeases[1].ID {
|
|
t.Fatalf("active leases must renew attempt and admission ownership together: %+v", active)
|
|
}
|
|
if len(release) != 1 || release[0].ID != attemptLease.ID {
|
|
t.Fatalf("attempt cleanup must not release task-scoped admission leases: %+v", release)
|
|
}
|
|
|
|
// A same-platform retry receives the same admission lease IDs. The first
|
|
// attempt cleanup must leave them renewable by the next attempt.
|
|
retryActive, retryRelease := bindAttemptConcurrencyLeases(nil, admissionLeases)
|
|
if len(retryActive) != 2 || retryActive[0].ID != admissionLeases[0].ID || retryActive[1].ID != admissionLeases[1].ID {
|
|
t.Fatalf("retry must keep using the live admission leases: %+v", retryActive)
|
|
}
|
|
if len(retryRelease) != 0 {
|
|
t.Fatalf("retry without attempt-owned leases must not release admission leases: %+v", retryRelease)
|
|
}
|
|
}
|