optimize archive retry claim SQL
This commit is contained in:
parent
90ab87393e
commit
523cfe961f
@ -113,16 +113,32 @@ func (s *Service) claimArchiveRows(ctx context.Context, batchSize int) ([]model.
|
|||||||
rows = append(rows, staleRows...)
|
rows = append(rows, staleRows...)
|
||||||
}
|
}
|
||||||
if remaining := batchSize - len(rows); remaining > 0 {
|
if remaining := batchSize - len(rows); remaining > 0 {
|
||||||
var retryableRows []model.TaskCenterEventArchiveOutbox
|
pendingLimit := taskCenterArchivePendingClaimLimit(remaining)
|
||||||
// PENDING/FAILED 只按状态和创建时间抢占,避免和 PROCESSING 超时接管揉成 OR 后放大扫描。
|
for _, retryable := range []struct {
|
||||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE", Options: "SKIP LOCKED"}).
|
status string
|
||||||
Where("status IN ?", []string{ArchiveStatusPending, ArchiveStatusFailed}).
|
limit int
|
||||||
Order("create_time asc, id asc").
|
}{
|
||||||
Limit(remaining).
|
{status: ArchiveStatusPending, limit: pendingLimit},
|
||||||
Find(&retryableRows).Error; err != nil {
|
{status: ArchiveStatusFailed, limit: remaining},
|
||||||
return err
|
} {
|
||||||
|
if retryable.limit <= 0 || remaining <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if retryable.limit > remaining {
|
||||||
|
retryable.limit = remaining
|
||||||
|
}
|
||||||
|
var retryableRows []model.TaskCenterEventArchiveOutbox
|
||||||
|
// PENDING 和 FAILED 分开抢占,避免 IN 跨 status 排序触发 filesort,同时给 FAILED 保留重试额度。
|
||||||
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE", Options: "SKIP LOCKED"}).
|
||||||
|
Where("status = ?", retryable.status).
|
||||||
|
Order("create_time asc, id asc").
|
||||||
|
Limit(retryable.limit).
|
||||||
|
Find(&retryableRows).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rows = append(rows, retryableRows...)
|
||||||
|
remaining -= len(retryableRows)
|
||||||
}
|
}
|
||||||
rows = append(rows, retryableRows...)
|
|
||||||
}
|
}
|
||||||
if len(rows) == 0 {
|
if len(rows) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -164,6 +180,20 @@ func taskCenterArchiveClaimLimits(batchSize int) (int, int) {
|
|||||||
return staleLimit, batchSize - staleLimit
|
return staleLimit, batchSize - staleLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func taskCenterArchivePendingClaimLimit(retryableLimit int) int {
|
||||||
|
if retryableLimit <= 1 {
|
||||||
|
return retryableLimit
|
||||||
|
}
|
||||||
|
failedReserve := retryableLimit / 10
|
||||||
|
if failedReserve < 1 {
|
||||||
|
failedReserve = 1
|
||||||
|
}
|
||||||
|
if failedReserve > 100 {
|
||||||
|
failedReserve = 100
|
||||||
|
}
|
||||||
|
return retryableLimit - failedReserve
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) newCOSClient() (*cos.Client, error) {
|
func (s *Service) newCOSClient() (*cos.Client, error) {
|
||||||
bucketURL, err := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com",
|
bucketURL, err := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com",
|
||||||
strings.TrimSpace(s.cfg.TaskCenter.Archive.Bucket),
|
strings.TrimSpace(s.cfg.TaskCenter.Archive.Bucket),
|
||||||
|
|||||||
@ -87,6 +87,28 @@ func TestTaskCenterArchiveClaimLimitsReserveStaleRows(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTaskCenterArchivePendingClaimLimitReservesFailedRows(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
retryableLimit int
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
{name: "empty", retryableLimit: 0, want: 0},
|
||||||
|
{name: "single row stays pending first", retryableLimit: 1, want: 1},
|
||||||
|
{name: "small retry batch keeps one failed slot", retryableLimit: 4, want: 3},
|
||||||
|
{name: "normal retry batch reserves ten percent", retryableLimit: 450, want: 405},
|
||||||
|
{name: "large retry batch caps failed reserve", retryableLimit: 900, want: 810},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := taskCenterArchivePendingClaimLimit(tt.retryableLimit); got != tt.want {
|
||||||
|
t.Fatalf("taskCenterArchivePendingClaimLimit(%d) = %d, want %d", tt.retryableLimit, got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDailyTaskConfigEventListAndClaim(t *testing.T) {
|
func TestDailyTaskConfigEventListAndClaim(t *testing.T) {
|
||||||
java := &taskCenterTestGateway{events: map[string]bool{}}
|
java := &taskCenterTestGateway{events: map[string]bool{}}
|
||||||
service, db := newTestService(t, java)
|
service, db := newTestService(t, java)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user