func TestLockContestDuo(t *testing.T) { assert := assert.New(t) // Instantiation c := cluster.NewRedisCluster(rConfig) assert.NotEmpty(c) defer c.Close() // Create 2 locks on the same key key := RandomKey() locks := []*lock.Lock{ lock.CreateLock(c, key), lock.CreateLock(c, key), } // Unlease dogs of war result := make(chan int, 2) acquired := 0 for _, l := range locks { func(l *lock.Lock) { go func() { success, err := l.Get(false) assert.Empty(err) if success { acquired++ } result <- 1 }() }(l) } // Wait for them to finish <-result <-result assert.Equal(acquired, 1) }
func TestLockAutoExpire(t *testing.T) { assert := assert.New(t) // Instantiation c := cluster.NewRedisCluster(rConfig) assert.NotEmpty(c) defer c.Close() // Create lock key := RandomKey() l1 := lock.CreateLock(c, key) duration := 3 * time.Second l1.Duration = duration l2 := lock.CreateLock(c, key) // Acquire lock success, err := l1.Get(false) assert.Empty(err) assert.True(success) // Acquire lock on the same key, should fail success, err = l2.Get(false) assert.Empty(err) assert.False(success) // Sleep past the expiration time time.Sleep(duration) // Acquire lock, should succeed this time success, err = l2.Get(false) assert.Empty(err) assert.True(success) }
func TestLockRelease(t *testing.T) { assert := assert.New(t) // Instantiation c := cluster.NewRedisCluster(rConfig) assert.NotEmpty(c) defer c.Close() // Create lock key := RandomKey() l1 := lock.CreateLock(c, key) l1.Duration = 16 * time.Second l2 := lock.CreateLock(c, key) // Acquire lock success, err := l1.Get(false) assert.Empty(err) assert.True(success) assert.True(l1.IsActive()) // Acquire lock on the same key, should fail success, err = l2.Get(false) assert.Empty(err) assert.False(success) assert.False(l2.IsActive()) // Release original lock success, err = l1.Release() assert.Empty(err) assert.True(success) assert.False(l1.IsActive()) // Acquire lock, should succeed this time success, err = l2.Get(false) assert.Empty(err) assert.True(success) assert.True(l2.IsActive()) }
func TestLockMutualExclusion(t *testing.T) { assert := assert.New(t) // Instantiation c := cluster.NewRedisCluster(rConfig) assert.NotEmpty(c) defer c.Close() // Create locks key := RandomKey() l1 := lock.CreateLock(c, key) l2 := lock.CreateLock(c, key) l1.Duration = 3 * time.Second l2.Duration = 3 * time.Second // Acquire lock on l1 success, err := l1.Get(false) assert.Empty(err) assert.True(success) assert.True(l1.IsActive()) // Acquire lock on l2, should fail success, err = l2.Get(false) assert.Empty(err) assert.False(success) assert.False(l2.IsActive()) }
func TestLockAcquisition(t *testing.T) { assert := assert.New(t) // Instantiation c := cluster.NewRedisCluster(rConfig) assert.NotEmpty(c) defer c.Close() // Create lock key := RandomKey() l := lock.CreateLock(c, key) l.Duration = 3 * time.Second // Acquire lock success, err := l.Get(false) assert.Empty(err) assert.True(success) assert.True(l.IsActive()) }
func TestLockContestTrio(t *testing.T) { assert := assert.New(t) // Instantiation clusters := []*cluster.RedisCluster{ cluster.NewRedisCluster(rConfig), cluster.NewRedisCluster(rConfig), cluster.NewRedisCluster(rConfig), } defer func() { for _, c := range clusters { c.Close() } }() // Create 3 locks on the same key key := RandomKey() locks := []*lock.Lock{} for _, c := range clusters { l := lock.CreateLock(c, key) locks = append(locks, l) } // Unlease dogs of war result := make(chan int, 3) acquired := 0 for _, l := range locks { func(l *lock.Lock) { go func() { success, err := l.Get(false) assert.Empty(err) if success { acquired++ } result <- 1 }() }(l) } // Wait for them to finish for i := 0; i < 3; i++ { <-result } assert.True(acquired <= 1) }
func (m *Magi) process(queueName string, id string) { var _lock *lock.Lock // Catch panics defer func() { if err := recover(); err != nil { err, ok := err.(error) if ok && err.Error() == lock.ErrLockLost.Error() { // Lock is lost, release remaining lock segments _lock.Release() } else { panic(err) } } }() // Check if the processor is available processor, exists := m.processors[queueName] if !exists { return } // Get job details _job, err := m.GetJob(id) if err != nil { return } // Acquire lock _lock = lock.CreateLock(m.rCluster, id) result, err := _lock.Get((*processor).ShouldAutoRenew(_job)) // If lock cannot be acquired, return and do not acknowledge if err != nil { return } if !result { return } // Start the auto wait extension for the job in queue control := make(chan bool, 1) _job.IsProcessing = true go m.autoWait(_job, &control) // Process the job (*processor).Process(_job) // Stop the auto wait extension _job.IsProcessing = false control <- true // Ack the job err = m.dqCluster.Ack(id) if err != nil { return } if !result { return } // Release the lock result, err = _lock.Release() if err != nil { return } if !result { return } return }