73 lines
1.5 KiB
Go
73 lines
1.5 KiB
Go
package dispatcher
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"git.ipao.vip/rogee/go-sip/internal/store"
|
|
)
|
|
|
|
const activeLeaseScope = "dispatcher"
|
|
|
|
type LeaseGuard struct {
|
|
store *store.Store
|
|
leaseID string
|
|
scope string
|
|
holder string
|
|
ttl time.Duration
|
|
stop chan struct{}
|
|
done chan struct{}
|
|
lost chan error
|
|
once sync.Once
|
|
}
|
|
|
|
func StartLease(ctx context.Context, s *store.Store, leaseID, scope, holder string, ttl time.Duration) (*LeaseGuard, error) {
|
|
if ctx == nil {
|
|
return nil, fmt.Errorf("lease context is required")
|
|
}
|
|
lease, err := s.AcquireLease(leaseID, scope, holder, ttl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
guard := &LeaseGuard{store: s, leaseID: lease.LeaseID, scope: scope, holder: holder, ttl: ttl, stop: make(chan struct{}), done: make(chan struct{}), lost: make(chan error, 1)}
|
|
go guard.renew(ctx)
|
|
return guard, nil
|
|
}
|
|
|
|
func (g *LeaseGuard) renew(ctx context.Context) {
|
|
defer close(g.done)
|
|
ticker := time.NewTicker(g.ttl / 3)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-g.stop:
|
|
return
|
|
case <-ticker.C:
|
|
if _, err := g.store.AcquireLease(g.leaseID, g.scope, g.holder, g.ttl); err != nil {
|
|
select {
|
|
case g.lost <- err:
|
|
default:
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *LeaseGuard) Lost() <-chan error { return g.lost }
|
|
|
|
func (g *LeaseGuard) Stop() error {
|
|
if g == nil {
|
|
return nil
|
|
}
|
|
g.once.Do(func() {
|
|
close(g.stop)
|
|
<-g.done
|
|
})
|
|
return g.store.ReleaseLease(g.leaseID)
|
|
}
|