diff --git a/contrib/recipes/barrier.go b/contrib/recipes/barrier.go index 5ab4817c718..38b51129cab 100644 --- a/contrib/recipes/barrier.go +++ b/contrib/recipes/barrier.go @@ -49,7 +49,7 @@ func (b *Barrier) Release() error { // Wait blocks on the barrier key until it is deleted. If there is no key, Wait // assumes Release has already been called and returns immediately. func (b *Barrier) Wait() error { - resp, err := b.client.Get(b.ctx, b.key, v3.WithFirstKey()...) + resp, err := b.client.Get(b.ctx, b.key) if err != nil { return err } diff --git a/integration/v3_barrier_test.go b/integration/v3_barrier_test.go index 1fbc78b3c6a..4f1f1fda9ee 100644 --- a/integration/v3_barrier_test.go +++ b/integration/v3_barrier_test.go @@ -76,3 +76,42 @@ func testBarrier(t *testing.T, waiters int, chooseClient func() *clientv3.Client } } } + +func TestBarrierWaitNonexistentKey(t *testing.T) { + defer testutil.AfterTest(t) + clus := NewClusterV3(t, &ClusterConfig{Size: 1}) + defer clus.Terminate(t) + cli := clus.clients[0] + + if _, err := cli.Put(cli.Ctx(), "test-barrier-0", ""); err != nil { + t.Errorf("could not put test-barrier0, err:%v", err) + } + + donec := make(chan struct{}) + stopc := make(chan struct{}) + defer close(stopc) + + waiters := 5 + for i := 0; i < waiters; i++ { + go func() { + br := recipe.NewBarrier(cli, "test-barrier") + if err := br.Wait(); err != nil { + t.Errorf("could not wait on barrier (%v)", err) + } + select { + case donec <- struct{}{}: + case <-stopc: + } + }() + } + + // all waiters should return immediately if waiting on a nonexistent key "test-barrier" even if key "test-barrier-0" exists + timerC := time.After(time.Duration(waiters*100) * time.Millisecond) + for i := 0; i < waiters; i++ { + select { + case <-timerC: + t.Fatal("barrier timed out") + case <-donec: + } + } +}