mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-07-06 20:03:23 +08:00
* fix: performance issues with Kafka caused by encapsulating the MQ interface * fix: admin token in standalone mode * fix: full id version * fix: resolve deadlock in cache eviction and improve GetBatch implementation * refactor: replace LongConn with ClientConn interface and simplify message handling * refactor: replace LongConn with ClientConn interface and simplify message handling * fix: seq use $setOnInsert for min_seq in conversation update * feat: add error code for handled friend requests and improve error handling in friend operations * refactor(msg): update regex pattern for conversationID to include a trailing colon * refactor: streamline cache initialization and enhance queue engine configuration * refactor: streamline cache initialization and enhance queue engine configuration * feat: add RegisterIP to API config and implement Redis server registration * feat(redis): implement standalone gateway registration with Redis * chore: update openimsdk/tools dependency to v0.0.50-alpha.121 * fix: change timer to ticker for improved periodic execution * refactor: replace Kafka topic configuration with mqbuild constants for improved readability * feat(redis): implement Redis-based locking mechanism for cron tasks
84 lines
1.9 KiB
Go
84 lines
1.9 KiB
Go
package cron
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
clientv3 "go.etcd.io/etcd/client/v3"
|
|
"go.etcd.io/etcd/client/v3/concurrency"
|
|
|
|
"github.com/openimsdk/tools/log"
|
|
)
|
|
|
|
type EtcdLocker struct {
|
|
client *clientv3.Client
|
|
instanceID string
|
|
}
|
|
|
|
// NewEtcdLocker creates a new etcd distributed lock
|
|
func NewEtcdLocker(client *clientv3.Client) (*EtcdLocker, error) {
|
|
hostname, _ := os.Hostname()
|
|
pid := os.Getpid()
|
|
instanceID := fmt.Sprintf("%s-pid-%d-%d", hostname, pid, time.Now().UnixNano())
|
|
|
|
locker := &EtcdLocker{
|
|
client: client,
|
|
instanceID: instanceID,
|
|
}
|
|
|
|
return locker, nil
|
|
}
|
|
|
|
func (e *EtcdLocker) ExecuteWithLock(ctx context.Context, taskName string, task func()) {
|
|
session, err := concurrency.NewSession(e.client, concurrency.WithTTL(int(lockLeaseTTL/time.Second)))
|
|
if err != nil {
|
|
log.ZWarn(ctx, "Failed to create etcd session", err,
|
|
"taskName", taskName,
|
|
"instanceID", e.instanceID)
|
|
return
|
|
}
|
|
defer session.Close()
|
|
|
|
lockKey := fmt.Sprintf("openim/crontask/%s", taskName)
|
|
mutex := concurrency.NewMutex(session, lockKey)
|
|
|
|
ctxWithTimeout, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
|
defer cancel()
|
|
|
|
err = mutex.TryLock(ctxWithTimeout)
|
|
if err != nil {
|
|
// errors.Is(err, concurrency.ErrLocked)
|
|
log.ZDebug(ctx, "Task is being executed by another instance, skipping",
|
|
"taskName", taskName,
|
|
"instanceID", e.instanceID,
|
|
"error", err.Error())
|
|
|
|
return
|
|
}
|
|
|
|
defer func() {
|
|
if err := mutex.Unlock(ctx); err != nil {
|
|
log.ZWarn(ctx, "Failed to release task lock", err,
|
|
"taskName", taskName,
|
|
"instanceID", e.instanceID)
|
|
} else {
|
|
log.ZInfo(ctx, "Successfully released task lock",
|
|
"taskName", taskName,
|
|
"instanceID", e.instanceID)
|
|
}
|
|
}()
|
|
|
|
log.ZInfo(ctx, "Successfully acquired task lock, starting execution",
|
|
"taskName", taskName,
|
|
"instanceID", e.instanceID,
|
|
"sessionID", session.Lease())
|
|
|
|
task()
|
|
|
|
log.ZInfo(ctx, "Task execution completed",
|
|
"taskName", taskName,
|
|
"instanceID", e.instanceID)
|
|
}
|