diff --git a/lock_redis.go b/lock_redis.go index 6a16fd5..c3634d5 100644 --- a/lock_redis.go +++ b/lock_redis.go @@ -18,7 +18,7 @@ var ( // Lock 加锁 func (lock *RedisLock) Lock() error { - result, err := lock.redis.Eval(lock.Context, reentrantLockScript, []string{lock.key}, lock.token, lock.lockTimeout.Seconds()).Result() + result, err := lock.redis.Eval(lock.Context, reentrantLockScript, []string{lock.key}, lock.token, lock.lockTimeout.Milliseconds()).Result() if err != nil { return ErrException @@ -79,7 +79,7 @@ func (lock *RedisLock) SpinLock(timeout time.Duration) error { // Renew 锁手动续期 func (lock *RedisLock) Renew() error { - res, err := lock.redis.Eval(lock.Context, reentrantRenewScript, []string{lock.key}, lock.token, lock.lockTimeout.Seconds()).Result() + res, err := lock.redis.Eval(lock.Context, reentrantRenewScript, []string{lock.key}, lock.token, lock.lockTimeout.Milliseconds()).Result() if err != nil { return ErrException diff --git a/lock_redis_local_test.go b/lock_redis_local_test.go index 8bfbce1..0d773b6 100644 --- a/lock_redis_local_test.go +++ b/lock_redis_local_test.go @@ -26,7 +26,7 @@ func TestLockSuccess(t *testing.T) { lock := New(ctx, db, key, WithToken(token)) // 设置模拟锁获取成功的行为 - mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") err := lock.Lock() if err != nil { @@ -53,7 +53,7 @@ func TestLockFail(t *testing.T) { ctx := context.Background() db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") var wg sync.WaitGroup wg.Add(2) @@ -111,7 +111,7 @@ func TestUnlockFail(t *testing.T) { lock := New(ctx, db, key, WithToken(token)) // 加锁逻辑 - mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") err := lock.Lock() if err != nil { @@ -142,8 +142,8 @@ func TestSpinLockSuccess(t *testing.T) { token2 := "some_token2" spinTimeout := time.Duration(5) * time.Second - mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") - mock.ExpectEval(reentrantLockScript, []string{key}, token2, lockTime.Seconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token2, lockTime.Milliseconds()).SetVal("OK") var wg sync.WaitGroup wg.Add(2) @@ -192,8 +192,8 @@ func TestSpinLockTimeout(t *testing.T) { spinTimeout := time.Duration(5) * time.Second spinTimeout2 := time.Duration(3) * time.Second - mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") - mock.ExpectEval(reentrantLockScript, []string{key}, token2, lockTime.Seconds()).SetVal("nil") + mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token2, lockTime.Milliseconds()).SetVal("nil") var wg sync.WaitGroup wg.Add(2) @@ -238,8 +238,8 @@ func TestRenewSuccess(t *testing.T) { key := "test_key_TestRenewSuccess" token := "some_token" - mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") - mock.ExpectEval(reentrantRenewScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") + mock.ExpectEval(reentrantRenewScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") // 设置模拟锁续期成功的行为 mock.ExpectExpire(key, lockTime).SetVal(true) @@ -283,7 +283,7 @@ func TestRenewFail(t *testing.T) { key := "test_key_TestRenewFail" token := "some_token" - mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") // 设置模拟锁续期成功的行为 mock.ExpectExpire(key, lockTime).SetVal(false) @@ -328,7 +328,7 @@ func TestWithTimeout(t *testing.T) { token := "some_token" timeout := time.Duration(10) * time.Second - mock.ExpectEval(reentrantLockScript, []string{key}, token, timeout.Seconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token, timeout.Milliseconds()).SetVal("OK") var wg sync.WaitGroup wg.Add(2) @@ -375,8 +375,8 @@ func TestAutoRenew(t *testing.T) { key := "test_key_TestAutoRenew" token := "some_token" - mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") - mock.ExpectEval(reentrantRenewScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") + mock.ExpectEval(reentrantLockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") + mock.ExpectEval(reentrantRenewScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") mock.ExpectExpire(key, lockTime).SetVal(true) lock := New(ctx, db, key, WithToken(token), WithAutoRenew()) @@ -400,7 +400,7 @@ func TestAutoRenew(t *testing.T) { // token := "some_token" // // // 设置模拟锁获取成功的行为 -// mock.ExpectEval(lockScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") +// mock.ExpectEval(lockScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") // // 设置模拟锁续期成功的行为 // mock.ExpectExpire(key, lockTime).SetVal(true) // @@ -414,7 +414,7 @@ func TestAutoRenew(t *testing.T) { // go func() { // defer wg.Done() // // 模拟锁续期成功 -// mock.ExpectEval(renewScript, []string{key}, token, lockTime.Seconds()).SetVal("OK") +// mock.ExpectEval(renewScript, []string{key}, token, lockTime.Milliseconds()).SetVal("OK") // // 等待一段时间,模拟自动续期的过程 // time.Sleep(time.Second * 3) // // 取消上下文,模拟上下文的取消 @@ -515,7 +515,7 @@ func TestSevLockSuccess(t *testing.T) { lock := New(ctx, redisClient, key) times, _ := redisClient.TTL(ctx, key).Result() - log.Println("线程二:ttl 时间:", times.Seconds()) + log.Println("线程二:ttl 时间:", times.Milliseconds()) err := lock.Lock() if err == nil { diff --git a/lock_redis_test.go b/lock_redis_test.go index cd0bc25..bacb77a 100644 --- a/lock_redis_test.go +++ b/lock_redis_test.go @@ -22,7 +22,7 @@ func TestRedisLock_Lock(t *testing.T) { name: "加锁成功", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") return db }, @@ -34,7 +34,7 @@ func TestRedisLock_Lock(t *testing.T) { name: "加锁内部异常", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetErr(ErrException) return db }, @@ -46,7 +46,7 @@ func TestRedisLock_Lock(t *testing.T) { name: "加锁失败", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("nil") return db }, @@ -79,7 +79,7 @@ func TestRedisLock_UnLock(t *testing.T) { name: "解锁成功", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") mock.ExpectEval(reentrantUnLockScript, []string{"key"}, "token"). SetVal("OK") @@ -99,7 +99,7 @@ func TestRedisLock_UnLock(t *testing.T) { name: "解锁内部异常", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") mock.ExpectEval(reentrantUnLockScript, []string{"key"}, "token"). SetErr(ErrException) @@ -119,7 +119,7 @@ func TestRedisLock_UnLock(t *testing.T) { name: "解锁失败", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") mock.ExpectEval(reentrantUnLockScript, []string{"key"}, "token"). SetVal("nil") @@ -166,7 +166,7 @@ func TestRedisLock_SpinLock(t *testing.T) { name: "自旋锁-加锁成功", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") return db }, @@ -185,7 +185,7 @@ func TestRedisLock_SpinLock(t *testing.T) { name: "自旋锁-加锁超时", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") return db }, @@ -210,7 +210,7 @@ func TestRedisLock_SpinLock(t *testing.T) { name: "自旋锁-Ctx取消", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") return db }, @@ -267,9 +267,9 @@ func TestRedisLock_LockRenew(t *testing.T) { name: "锁手动续期成功", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") - mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") return db }, @@ -287,9 +287,9 @@ func TestRedisLock_LockRenew(t *testing.T) { name: "锁手动续期异常", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") - mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Milliseconds()). SetErr(ErrException) return db }, @@ -307,9 +307,9 @@ func TestRedisLock_LockRenew(t *testing.T) { name: "锁手动续期失败", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") - mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("nil") return db }, @@ -362,9 +362,9 @@ func TestRedisLock_LockAutoRenew(t *testing.T) { name: "锁自动续期成功", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") - mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") return db }, @@ -382,9 +382,9 @@ func TestRedisLock_LockAutoRenew(t *testing.T) { name: "锁自动续期-Ctx取消", mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") - mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Seconds()). + mock.ExpectEval(reentrantRenewScript, []string{"key"}, "token", lockTime.Milliseconds()). SetVal("OK") return db }, @@ -440,10 +440,10 @@ func TestRedisLock_LockTimeout(t *testing.T) { mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() // 第一次加锁 - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", (time.Second * 2).Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", (time.Second * 2).Milliseconds()). SetVal("OK") // 第二次加锁 - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", (time.Second * 2).Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", (time.Second * 2).Milliseconds()). SetVal("OK") // 第一次解锁 @@ -476,10 +476,10 @@ func TestRedisLock_LockTimeout(t *testing.T) { mock: func(t *testing.T) *redis.Client { db, mock := redismock.NewClientMock() // 第一次加锁 - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", (time.Second * 5).Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", (time.Second * 5).Milliseconds()). SetVal("OK") // 第二次加锁 - mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", (time.Second * 5).Seconds()). + mock.ExpectEval(reentrantLockScript, []string{"key"}, "token", (time.Second * 5).Milliseconds()). SetVal("nil") // 第一次解锁 diff --git a/lua/reentrantLock.lua b/lua/reentrantLock.lua index 396ef0f..4b27b32 100644 --- a/lua/reentrantLock.lua +++ b/lua/reentrantLock.lua @@ -7,15 +7,15 @@ local reentrant_count = tonumber(redis.call('GET', reentrant_key) or '0') -- 可重入锁计数器 if reentrant_count > 0 then redis.call('INCR', reentrant_key) - redis.call('EXPIRE', lock_key, lock_ttl) - redis.call('EXPIRE', reentrant_key, lock_ttl) + redis.call('PEXPIRE', lock_key, lock_ttl) + redis.call('PEXPIRE', reentrant_key, lock_ttl) return "OK" end -- 创建锁 -if redis.call('SET', lock_key, lock_value, 'NX', 'EX', lock_ttl) then +if redis.call('SET', lock_key, lock_value, 'NX', 'PX', lock_ttl) then redis.call('SET', reentrant_key, 1) - redis.call('EXPIRE', reentrant_key, lock_ttl) + redis.call('PEXPIRE', reentrant_key, lock_ttl) return "OK" end diff --git a/lua/reentrantRenew.lua b/lua/reentrantRenew.lua index 7e50203..2d1caef 100644 --- a/lua/reentrantRenew.lua +++ b/lua/reentrantRenew.lua @@ -8,8 +8,8 @@ local reentrant_count = tonumber(redis.call('GET', reentrant_key) or '0') -- 重入锁的场景(reentrant_count > 0) -- 普通锁的场景(redis.call('GET', lock_key) == lock_value) if reentrant_count > 0 or redis.call('GET', lock_key) == lock_value then - redis.call('EXPIRE', lock_key, lock_ttl) - redis.call('EXPIRE', reentrant_key, lock_ttl) + redis.call('PEXPIRE', lock_key, lock_ttl) + redis.call('PEXPIRE', reentrant_key, lock_ttl) return "OK" end