embed: Move the ReadyNotify() call to a better place
When using the embed functionality, you can't call the Server.Stop() function until StartEtcd returns, which can block until there is a call to Server.Stop() in error situations. Since we have a catch-22, the ReadyNotify() can be called manually by the user if they wish to wait for the server startup, or in parallel with a timeout if they wish to cancel it after some time. Chzz pointed out that this is also more consistent with the etcdserver.Start() behaviour too. purpleidea pointed out that this is actually more correct too, because we can now register the stop interrupt handler before we block on startup.
This commit is contained in:
@ -19,6 +19,7 @@ Launch an embedded etcd server using the configuration defaults:
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/embed"
|
||||
)
|
||||
@ -31,6 +32,13 @@ Launch an embedded etcd server using the configuration defaults:
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer e.Close()
|
||||
select {
|
||||
case <-e.Server.ReadyNotify():
|
||||
log.Printf("Server is ready!")
|
||||
case <-time.After(60 * time.Second):
|
||||
e.Server.Stop() // trigger a shutdown
|
||||
log.Printf("Server took too long to start!")
|
||||
}
|
||||
log.Fatal(<-e.Err())
|
||||
}
|
||||
*/
|
||||
|
@ -59,6 +59,8 @@ type Etcd struct {
|
||||
}
|
||||
|
||||
// StartEtcd launches the etcd server and HTTP handlers for client/server communication.
|
||||
// The returned Etcd.Server is not guaranteed to have joined the cluster. Wait
|
||||
// on the Etcd.Server.ReadyNotify() channel to know when it completes and is ready for use.
|
||||
func StartEtcd(inCfg *Config) (e *Etcd, err error) {
|
||||
if err = inCfg.Validate(); err != nil {
|
||||
return nil, err
|
||||
@ -130,7 +132,6 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
|
||||
if err = e.serve(); err != nil {
|
||||
return
|
||||
}
|
||||
<-e.Server.ReadyNotify()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -186,6 +186,7 @@ func startEtcd(cfg *embed.Config) (<-chan struct{}, <-chan error, error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
osutil.RegisterInterruptHandler(e.Server.Stop)
|
||||
<-e.Server.ReadyNotify() // wait for e.Server to join the cluster
|
||||
return e.Server.StopNotify(), e.Err(), nil
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,9 @@ func TestEmbedEtcd(t *testing.T) {
|
||||
for i, tt := range tests {
|
||||
tests[i].cfg.Dir = dir
|
||||
e, err := embed.StartEtcd(&tests[i].cfg)
|
||||
if e != nil {
|
||||
<-e.Server.ReadyNotify() // wait for e.Server to join the cluster
|
||||
}
|
||||
if tt.werr != "" {
|
||||
if err == nil || !strings.Contains(err.Error(), tt.werr) {
|
||||
t.Errorf("%d: expected error with %q, got %v", i, tt.werr, err)
|
||||
|
Reference in New Issue
Block a user