Browse Source

clientv3: fix bad variable capture in watch request retry

variables would be niled out when the goroutine runs, causing a crash
Anthony Romano 10 years ago
parent
commit
3b7bd38a2d
2 changed files with 31 additions and 4 deletions
  1. 27 0
      clientv3/integration/watch_test.go
  2. 4 4
      clientv3/watch.go

+ 27 - 0
clientv3/integration/watch_test.go

@@ -157,6 +157,33 @@ func testWatchMultiWatcher(t *testing.T, wctx *watchctx) {
 	}
 }
 
+// TestWatchReconnRequest tests the send failure path when requesting a watcher.
+func TestWatchReconnRequest(t *testing.T) {
+	runWatchTest(t, testWatchReconnRequest)
+}
+
+func testWatchReconnRequest(t *testing.T, wctx *watchctx) {
+	// take down watcher connection
+	donec := make(chan struct{})
+	go func() {
+		for {
+			wctx.wclient.ActiveConnection().Close()
+			select {
+			case <-donec:
+				return
+			default:
+			}
+		}
+	}()
+	// should reconnect when requesting watch
+	if wctx.ch = wctx.w.Watch(context.TODO(), "a", 0); wctx.ch == nil {
+		t.Fatalf("expected non-nil channel")
+	}
+	close(donec)
+	// ensure watcher works
+	putAndWatch(t, wctx, "a", "a")
+}
+
 // TestWatchReconnInit tests watcher resumes correctly if connection lost
 // before any data was sent.
 func TestWatchReconnInit(t *testing.T) {

+ 4 - 4
clientv3/watch.go

@@ -286,13 +286,13 @@ func (w *watcher) run() {
 
 		// send failed; queue for retry
 		if failedReq != nil {
-			go func() {
+			go func(wr *watchRequest) {
 				select {
-				case w.reqc <- pendingReq:
-				case <-pendingReq.ctx.Done():
+				case w.reqc <- wr:
+				case <-wr.ctx.Done():
 				case <-w.donec:
 				}
-			}()
+			}(pendingReq)
 			failedReq = nil
 			pendingReq = nil
 		}