2020-01-18 23:32:06 +08:00
|
|
|
// Copyright 2020 Kentaro Hibino. All rights reserved.
|
|
|
|
// Use of this source code is governed by a MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package asynq
|
|
|
|
|
|
|
|
import (
|
2022-02-14 23:17:51 +08:00
|
|
|
"context"
|
2020-02-17 13:09:16 +08:00
|
|
|
"fmt"
|
2020-02-16 15:14:30 +08:00
|
|
|
"sync"
|
2020-01-18 23:32:06 +08:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
h "github.com/hibiken/asynq/internal/asynqtest"
|
|
|
|
"github.com/hibiken/asynq/internal/base"
|
|
|
|
"github.com/hibiken/asynq/internal/rdb"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestSyncer(t *testing.T) {
|
|
|
|
inProgress := []*base.TaskMessage{
|
|
|
|
h.NewTaskMessage("send_email", nil),
|
|
|
|
h.NewTaskMessage("reindex", nil),
|
|
|
|
h.NewTaskMessage("gen_thumbnail", nil),
|
|
|
|
}
|
|
|
|
r := setup(t)
|
2020-09-08 21:51:01 +08:00
|
|
|
defer r.Close()
|
2020-01-18 23:32:06 +08:00
|
|
|
rdbClient := rdb.NewRDB(r)
|
2020-09-06 03:43:15 +08:00
|
|
|
h.SeedActiveQueue(t, r, inProgress, base.DefaultQueueName)
|
2020-01-18 23:32:06 +08:00
|
|
|
|
|
|
|
const interval = time.Second
|
|
|
|
syncRequestCh := make(chan *syncRequest)
|
2020-05-18 03:33:55 +08:00
|
|
|
syncer := newSyncer(syncerParams{
|
|
|
|
logger: testLogger,
|
|
|
|
requestsCh: syncRequestCh,
|
|
|
|
interval: interval,
|
|
|
|
})
|
2020-02-16 15:14:30 +08:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
syncer.start(&wg)
|
2021-03-23 21:20:54 +08:00
|
|
|
defer syncer.shutdown()
|
2020-01-18 23:32:06 +08:00
|
|
|
|
|
|
|
for _, msg := range inProgress {
|
|
|
|
m := msg
|
|
|
|
syncRequestCh <- &syncRequest{
|
|
|
|
fn: func() error {
|
2022-02-14 23:17:51 +08:00
|
|
|
return rdbClient.Done(context.Background(), m)
|
2020-01-18 23:32:06 +08:00
|
|
|
},
|
2020-06-19 20:51:50 +08:00
|
|
|
deadline: time.Now().Add(5 * time.Minute),
|
2020-01-18 23:32:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-19 02:17:39 +08:00
|
|
|
time.Sleep(2 * interval) // ensure that syncer runs at least once
|
2020-01-18 23:32:06 +08:00
|
|
|
|
2020-09-06 03:43:15 +08:00
|
|
|
gotActive := h.GetActiveMessages(t, r, base.DefaultQueueName)
|
|
|
|
if l := len(gotActive); l != 0 {
|
|
|
|
t.Errorf("%q has length %d; want 0", base.ActiveKey(base.DefaultQueueName), l)
|
2020-01-18 23:32:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncerRetry(t *testing.T) {
|
|
|
|
const interval = time.Second
|
|
|
|
syncRequestCh := make(chan *syncRequest)
|
2020-05-18 03:33:55 +08:00
|
|
|
syncer := newSyncer(syncerParams{
|
|
|
|
logger: testLogger,
|
|
|
|
requestsCh: syncRequestCh,
|
|
|
|
interval: interval,
|
|
|
|
})
|
2020-02-17 13:09:16 +08:00
|
|
|
|
2020-02-16 15:14:30 +08:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
syncer.start(&wg)
|
2021-03-23 21:20:54 +08:00
|
|
|
defer syncer.shutdown()
|
2020-01-18 23:32:06 +08:00
|
|
|
|
2020-02-17 13:09:16 +08:00
|
|
|
var (
|
|
|
|
mu sync.Mutex
|
|
|
|
counter int
|
|
|
|
)
|
|
|
|
|
|
|
|
// Increment the counter for each call.
|
|
|
|
// Initial call will fail and second call will succeed.
|
|
|
|
requestFunc := func() error {
|
|
|
|
mu.Lock()
|
|
|
|
defer mu.Unlock()
|
|
|
|
if counter == 0 {
|
|
|
|
counter++
|
|
|
|
return fmt.Errorf("zero")
|
2020-01-18 23:32:06 +08:00
|
|
|
}
|
2020-02-17 13:09:16 +08:00
|
|
|
counter++
|
|
|
|
return nil
|
2020-01-18 23:32:06 +08:00
|
|
|
}
|
|
|
|
|
2020-02-17 13:09:16 +08:00
|
|
|
syncRequestCh <- &syncRequest{
|
2020-06-19 20:51:50 +08:00
|
|
|
fn: requestFunc,
|
|
|
|
errMsg: "error",
|
|
|
|
deadline: time.Now().Add(5 * time.Minute),
|
2020-01-18 23:32:06 +08:00
|
|
|
}
|
|
|
|
|
2020-02-17 13:09:16 +08:00
|
|
|
// allow syncer to retry
|
|
|
|
time.Sleep(3 * interval)
|
2020-01-18 23:32:06 +08:00
|
|
|
|
2020-02-17 13:09:16 +08:00
|
|
|
mu.Lock()
|
|
|
|
if counter != 2 {
|
|
|
|
t.Errorf("counter = %d, want 2", counter)
|
2020-01-18 23:32:06 +08:00
|
|
|
}
|
2020-02-17 13:09:16 +08:00
|
|
|
mu.Unlock()
|
2020-01-18 23:32:06 +08:00
|
|
|
}
|
2020-06-19 20:51:50 +08:00
|
|
|
|
|
|
|
func TestSyncerDropsStaleRequests(t *testing.T) {
|
|
|
|
const interval = time.Second
|
|
|
|
syncRequestCh := make(chan *syncRequest)
|
|
|
|
syncer := newSyncer(syncerParams{
|
|
|
|
logger: testLogger,
|
|
|
|
requestsCh: syncRequestCh,
|
|
|
|
interval: interval,
|
|
|
|
})
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
syncer.start(&wg)
|
|
|
|
|
|
|
|
var (
|
|
|
|
mu sync.Mutex
|
|
|
|
n int // number of times request has been processed
|
|
|
|
)
|
|
|
|
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
syncRequestCh <- &syncRequest{
|
|
|
|
fn: func() error {
|
|
|
|
mu.Lock()
|
|
|
|
n++
|
|
|
|
mu.Unlock()
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
deadline: time.Now().Add(time.Duration(-i) * time.Second), // already exceeded deadline
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(2 * interval) // ensure that syncer runs at least once
|
2021-03-23 21:20:54 +08:00
|
|
|
syncer.shutdown()
|
2020-06-19 20:51:50 +08:00
|
|
|
|
|
|
|
mu.Lock()
|
|
|
|
if n != 0 {
|
|
|
|
t.Errorf("requests has been processed %d times, want 0", n)
|
|
|
|
}
|
|
|
|
mu.Unlock()
|
|
|
|
}
|