SQS: ValidateQueueName в createTenantQueue, JWT требует exp, leader сбрасывает лидерство при длительном сбое refresh
This commit is contained in:
+30
-5
@@ -33,16 +33,21 @@ type Elector struct {
|
||||
isLeader bool
|
||||
stopCh chan struct{}
|
||||
stopped bool
|
||||
|
||||
// lastRefresh — время последнего успешного refresh/acquire лока.
|
||||
// Нужен для сброса лидерства при длительном сбое refresh (split-brain).
|
||||
lastRefresh time.Time
|
||||
}
|
||||
|
||||
// New — создаёт Elector. key — ключ лока, id — уникальный id инстанса.
|
||||
func New(key, id string, ttl, interval time.Duration) *Elector {
|
||||
return &Elector{
|
||||
key: key,
|
||||
id: id,
|
||||
ttl: ttl,
|
||||
interval: interval,
|
||||
stopCh: make(chan struct{}),
|
||||
key: key,
|
||||
id: id,
|
||||
ttl: ttl,
|
||||
interval: interval,
|
||||
stopCh: make(chan struct{}),
|
||||
lastRefresh: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +113,15 @@ func (e *Elector) step() {
|
||||
ok, err := persistence.RefreshLock(e.key, e.id, e.ttl)
|
||||
if err != nil {
|
||||
log.Errorf("leader: refresh: %v", err)
|
||||
// Refresh не удаётся: если с последнего успеха прошло > TTL — лок
|
||||
// гарантированно истёк, и другой инстанс мог стать лидером (split-brain).
|
||||
// Сбрасываем лидерство (fail-safe), а не остаёмся «лидером» без лока.
|
||||
if time.Since(e.lastRefreshAt()) > e.ttl {
|
||||
e.setLeader(false)
|
||||
}
|
||||
return
|
||||
}
|
||||
e.markRefreshed()
|
||||
if !ok {
|
||||
e.setLeader(false)
|
||||
}
|
||||
@@ -122,5 +134,18 @@ func (e *Elector) step() {
|
||||
}
|
||||
if ok {
|
||||
e.setLeader(true)
|
||||
e.markRefreshed()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Elector) lastRefreshAt() time.Time {
|
||||
e.mu.RLock()
|
||||
defer e.mu.RUnlock()
|
||||
return e.lastRefresh
|
||||
}
|
||||
|
||||
func (e *Elector) markRefreshed() {
|
||||
e.mu.Lock()
|
||||
e.lastRefresh = time.Now()
|
||||
e.mu.Unlock()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user