Ver código fonte

etcdserver: stop raft loop when receiving stop signal

When it waits for apply to be done, it should stop the loop if it
receives stop signal.

This helps to print out panic information. Before this PR, if the panic
happens when server loop is applying entries, server loop will wait for
raft loop to stop forever.
Yicheng Qin 10 anos atrás
pai
commit
0814966ca2
2 arquivos alterados com 33 adições e 1 exclusões
  1. 5 1
      etcdserver/raft.go
  2. 28 0
      etcdserver/raft_test.go

+ 5 - 1
etcdserver/raft.go

@@ -161,7 +161,11 @@ func (r *raftNode) run() {
 
 
 			r.s.send(rd.Messages)
 			r.s.send(rd.Messages)
 
 
-			<-apply.done
+			select {
+			case <-apply.done:
+			case <-r.stopped:
+				return
+			}
 			r.Advance()
 			r.Advance()
 		case <-syncC:
 		case <-syncC:
 			r.s.sync(defaultSyncTimeout)
 			r.s.sync(defaultSyncTimeout)

+ 28 - 0
etcdserver/raft_test.go

@@ -18,9 +18,11 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"reflect"
 	"reflect"
 	"testing"
 	"testing"
+	"time"
 
 
 	"github.com/coreos/etcd/pkg/pbutil"
 	"github.com/coreos/etcd/pkg/pbutil"
 	"github.com/coreos/etcd/pkg/types"
 	"github.com/coreos/etcd/pkg/types"
+	"github.com/coreos/etcd/raft"
 	"github.com/coreos/etcd/raft/raftpb"
 	"github.com/coreos/etcd/raft/raftpb"
 )
 )
 
 
@@ -141,3 +143,29 @@ func TestCreateConfigChangeEnts(t *testing.T) {
 		}
 		}
 	}
 	}
 }
 }
+
+func TestStopRaftWhenWaitingForApplyDone(t *testing.T) {
+	n := newReadyNode()
+	r := raftNode{
+		Node:        n,
+		applyc:      make(chan apply),
+		storage:     &storageRecorder{},
+		raftStorage: raft.NewMemoryStorage(),
+		transport:   &nopTransporter{},
+	}
+	r.s = &EtcdServer{r: r}
+	go r.run()
+	n.readyc <- raft.Ready{}
+	select {
+	case <-r.applyc:
+	case <-time.After(time.Second):
+		t.Fatalf("failed to receive apply struct")
+	}
+
+	r.stopped <- struct{}{}
+	select {
+	case <-r.done:
+	case <-time.After(time.Second):
+		t.Fatalf("failed to stop raft loop")
+	}
+}