@@ -29,10 +29,11 @@ type Leaser interface {
29
29
// Etcd takes and holds a leader lease until it can no longer confirm it owns
30
30
// the lease, then returns.
31
31
type Etcd struct {
32
- client etcdclient.KeysAPI
33
- key string
34
- value string
35
- ttl uint64
32
+ client etcdclient.Client
33
+ keysClient etcdclient.KeysAPI
34
+ key string
35
+ value string
36
+ ttl uint64
36
37
37
38
// the fraction of the ttl to wait before trying to renew - for instance, 0.75 with TTL 20
38
39
// will wait 15 seconds before attempting to renew the lease, then retry over the next 5
@@ -51,10 +52,11 @@ type Etcd struct {
51
52
// client takes it.
52
53
func NewEtcd (client etcdclient.Client , key , value string , ttl uint64 ) Leaser {
53
54
return & Etcd {
54
- client : etcdclient .NewKeysAPI (client ),
55
- key : key ,
56
- value : value ,
57
- ttl : ttl ,
55
+ client : client ,
56
+ keysClient : etcdclient .NewKeysAPI (client ),
57
+ key : key ,
58
+ value : value ,
59
+ ttl : ttl ,
58
60
59
61
waitFraction : 0.66 ,
60
62
pauseInterval : time .Second ,
@@ -63,8 +65,30 @@ func NewEtcd(client etcdclient.Client, key, value string, ttl uint64) Leaser {
63
65
}
64
66
}
65
67
68
+ const autoSyncInterval = 10 * time .Second
69
+
66
70
// AcquireAndHold implements an acquire and release of a lease.
67
71
func (e * Etcd ) AcquireAndHold (notify chan error ) {
72
+ ctx , cancel := context .WithCancel (context .Background ())
73
+ defer cancel ()
74
+
75
+ go func () {
76
+ // Because the call to e.keysClient.Set in tryAcquire is using PrevNoExist, etcd considers this
77
+ // to be a "one-shot" attempt, meaning that if the connection attempt to one of the etcd cluster
78
+ // members fails, it will not fail over to any of the other cluster members. Calling
79
+ // e.client.AutoSync is not a one-shot call, and it will try to contact each cluster member
80
+ // until it succeeds. Assuming it does, the client's list of endpoints is updated, and any
81
+ // unavailable members are removed from the list.
82
+ for {
83
+ err := e .client .AutoSync (ctx , autoSyncInterval )
84
+ if err == context .DeadlineExceeded || err == context .Canceled {
85
+ break
86
+ }
87
+ utilruntime .HandleError (err )
88
+ time .Sleep (e .pauseInterval )
89
+ }
90
+ }()
91
+
68
92
for {
69
93
ok , ttl , index , err := e .tryAcquire ()
70
94
if err != nil {
@@ -96,7 +120,7 @@ func (e *Etcd) AcquireAndHold(notify chan error) {
96
120
func (e * Etcd ) tryAcquire () (ok bool , ttl uint64 , nextIndex uint64 , err error ) {
97
121
ttl = e .ttl
98
122
99
- resp , err := e .client .Set (
123
+ resp , err := e .keysClient .Set (
100
124
context .Background (),
101
125
e .key ,
102
126
e .value ,
@@ -116,7 +140,7 @@ func (e *Etcd) tryAcquire() (ok bool, ttl uint64, nextIndex uint64, err error) {
116
140
return false , 0 , 0 , fmt .Errorf ("unable to check lease %s: %v" , e .key , err )
117
141
}
118
142
119
- latest , err := e .client .Get (context .Background (), e .key , nil )
143
+ latest , err := e .keysClient .Get (context .Background (), e .key , nil )
120
144
if err != nil {
121
145
return false , 0 , 0 , fmt .Errorf ("unable to retrieve lease %s: %v" , e .key , err )
122
146
}
@@ -144,7 +168,7 @@ func (e *Etcd) tryAcquire() (ok bool, ttl uint64, nextIndex uint64, err error) {
144
168
// Release tries to delete the leader lock.
145
169
func (e * Etcd ) Release () {
146
170
for i := 0 ; i < e .maxRetries ; i ++ {
147
- _ , err := e .client .Delete (context .Background (), e .key , & etcdclient.DeleteOptions {PrevValue : e .value })
171
+ _ , err := e .keysClient .Delete (context .Background (), e .key , & etcdclient.DeleteOptions {PrevValue : e .value })
148
172
if err == nil {
149
173
break
150
174
}
@@ -197,7 +221,7 @@ func (e *Etcd) tryHold(ttl, index uint64) error {
197
221
case <- time .After (after ):
198
222
err := wait .Poll (interval , last , func () (bool , error ) {
199
223
glog .V (4 ).Infof ("Renewing lease %s at %d" , e .key , index - 1 )
200
- resp , err := e .client .Set (context .Background (), e .key , e .value ,
224
+ resp , err := e .keysClient .Set (context .Background (), e .key , e .value ,
201
225
& etcdclient.SetOptions {
202
226
TTL : time .Duration (e .ttl ) * time .Second ,
203
227
PrevValue : e .value ,
@@ -264,7 +288,7 @@ func (e *Etcd) waitExpiration(held bool, from uint64, stop chan struct{}) (bool,
264
288
default :
265
289
}
266
290
glog .V (5 ).Infof ("watching for expiration of lease %s from %d" , e .key , from )
267
- w := e .client .Watcher (e .key , & etcdclient.WatcherOptions {AfterIndex : from - 1 })
291
+ w := e .keysClient .Watcher (e .key , & etcdclient.WatcherOptions {AfterIndex : from - 1 })
268
292
resp , err := w .Next (context .Background ())
269
293
if err != nil {
270
294
return false , etcdIndexFor (err , from ), err
0 commit comments