parent
bfe8bcd9ad
commit
5882597ee1
@ -0,0 +1,14 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
lockLeaseTTL = time.Second * 300
|
||||
)
|
||||
|
||||
type Locker interface {
|
||||
ExecuteWithLock(ctx context.Context, taskName string, task func())
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/redis/go-redis/v9"
|
||||
|
||||
"github.com/openimsdk/tools/log"
|
||||
)
|
||||
|
||||
func NewRedisLocker(client redis.UniversalClient) *RedisLocker {
|
||||
return &RedisLocker{
|
||||
client: client,
|
||||
script: redis.NewScript(strings.TrimSpace(`
|
||||
if redis.call("get", KEYS[1]) == ARGV[1] then
|
||||
return redis.call("del", KEYS[1])
|
||||
else
|
||||
return 0
|
||||
end
|
||||
`)),
|
||||
}
|
||||
}
|
||||
|
||||
type RedisLocker struct {
|
||||
client redis.UniversalClient
|
||||
script *redis.Script
|
||||
}
|
||||
|
||||
func (e *RedisLocker) getKey(name string) string {
|
||||
return "CRON_LOCKED:" + name
|
||||
}
|
||||
|
||||
func (e *RedisLocker) lock(ctx context.Context, name string, owner string) (bool, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
||||
defer cancel()
|
||||
return e.client.SetNX(ctx, e.getKey(name), owner, lockLeaseTTL).Result()
|
||||
}
|
||||
|
||||
func (e *RedisLocker) unlock(ctx context.Context, name string, owner string) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
||||
defer cancel()
|
||||
return e.script.Run(ctx, e.client, []string{e.getKey(name)}, owner).Err()
|
||||
}
|
||||
|
||||
func (e *RedisLocker) ExecuteWithLock(ctx context.Context, taskName string, task func()) {
|
||||
owner := uuid.New().String()
|
||||
ok, err := e.lock(ctx, taskName, owner)
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "cron lock get lock", err, "taskName", taskName)
|
||||
return
|
||||
}
|
||||
log.ZDebug(ctx, "cron lock get lock", "taskName", taskName, "ok", ok, "owner", owner)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
err := e.unlock(ctx, taskName, owner)
|
||||
if err == nil {
|
||||
log.ZDebug(ctx, "cron lock unlock", "taskName", taskName, "owner", owner)
|
||||
} else {
|
||||
log.ZWarn(ctx, "cron lock unlock", err, "taskName", taskName, "owner", owner)
|
||||
}
|
||||
}()
|
||||
task()
|
||||
}
|
||||
Loading…
Reference in new issue