func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) { client := e.session.Client() defer close(ch) for { resp, err := client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...) if err != nil { return } var kv *mvccpb.KeyValue cctx, cancel := context.WithCancel(ctx) if len(resp.Kvs) == 0 { // wait for first key put on prefix opts := []v3.OpOption{v3.WithRev(resp.Header.Revision), v3.WithPrefix()} wch := client.Watch(cctx, e.keyPrefix, opts...) for kv == nil { wr, ok := <-wch if !ok || wr.Err() != nil { cancel() return } // only accept PUTs; a DELETE will make observe() spin for _, ev := range wr.Events { if ev.Type == mvccpb.PUT { kv = ev.Kv break } } } } else { kv = resp.Kvs[0] } wch := client.Watch(cctx, string(kv.Key), v3.WithRev(kv.ModRevision)) keyDeleted := false for !keyDeleted { wr, ok := <-wch if !ok { return } for _, ev := range wr.Events { if ev.Type == mvccpb.DELETE { keyDeleted = true break } resp.Header = &wr.Header resp.Kvs = []*mvccpb.KeyValue{ev.Kv} select { case ch <- *resp: case <-cctx.Done(): return } } } cancel() } }
// Leader returns the leader value for the current election. func (e *Election) Leader() (string, error) { resp, err := e.kv.Get(e.ctx, e.keyPrefix, v3.WithFirstCreate()...) if err != nil { return "", err } else if len(resp.Kvs) == 0 { // no leader currently elected return "", etcdserver.ErrNoLeader } return string(resp.Kvs[0].Value), nil }
// Leader returns the leader value for the current election. func (e *Election) Leader(ctx context.Context) (string, error) { resp, err := e.client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...) if err != nil { return "", err } else if len(resp.Kvs) == 0 { // no leader currently elected return "", ErrElectionNoLeader } return string(resp.Kvs[0].Value), nil }
// Wait waits for a leader to be elected, returning the leader value. func (e *Election) Wait() (string, error) { resp, err := e.kv.Get(e.ctx, e.keyPrefix, v3.WithFirstCreate()...) if err != nil { return "", err } else if len(resp.Kvs) != 0 { // leader already exists return string(resp.Kvs[0].Value), nil } _, err = WaitPrefixEvents( e.client, e.keyPrefix, resp.Header.Revision, []storagepb.Event_EventType{storagepb.PUT}) if err != nil { return "", err } return e.Wait() }