diff --git a/agent/agent.go b/agent/agent.go index 289653cd1b..9e161b3f0b 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -1908,11 +1908,6 @@ func (a *Agent) AddService(service *structs.NodeService, chkTypes []*structs.Che a.PauseSync() defer a.ResumeSync() - // Take a snapshot of the current state of checks (if any), and - // restore them before resuming anti-entropy. - snap := a.snapshotCheckState() - defer a.restoreCheckState(snap) - // Add the service a.State.AddService(service, token) @@ -2052,6 +2047,14 @@ func (a *Agent) AddCheck(check *structs.HealthCheck, chkType *structs.CheckType, a.checkLock.Lock() defer a.checkLock.Unlock() + // snapshot the current state of the health check to avoid potential flapping + existing := a.State.Check(check.CheckID) + defer func() { + if existing != nil { + a.State.UpdateCheck(check.CheckID, existing.Status, existing.Output) + } + }() + // Check if already registered if chkType != nil { switch { diff --git a/agent/agent_test.go b/agent/agent_test.go index 7551a59770..7db415343e 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -2467,7 +2467,7 @@ func TestAgent_Service_NoReap(t *testing.T) { } } -func TestAgent_addCheck_restoresSnapshot(t *testing.T) { +func TestAgent_AddService_restoresSnapshot(t *testing.T) { t.Parallel() a := NewTestAgent(t.Name(), "") defer a.Shutdown() @@ -2510,6 +2510,49 @@ func TestAgent_addCheck_restoresSnapshot(t *testing.T) { } } +func TestAgent_AddCheck_restoresSnapshot(t *testing.T) { + t.Parallel() + a := NewTestAgent(t.Name(), "") + defer a.Shutdown() + + // First register a service + svc := &structs.NodeService{ + ID: "redis", + Service: "redis", + Tags: []string{"foo"}, + Port: 8000, + } + if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil { + t.Fatalf("err: %v", err) + } + + // Register a check + check1 := &structs.HealthCheck{ + Node: a.Config.NodeName, + CheckID: "service:redis", + Name: "redischeck", + Status: api.HealthPassing, + ServiceID: "redis", + ServiceName: "redis", + } + if err := a.AddCheck(check1, nil, false, "", ConfigSourceLocal); err != nil { + t.Fatalf("err: %s", err) + } + + // Re-registering the check preserves its state + check1.Status = "" + if err := a.AddCheck(check1, &structs.CheckType{TTL: 30 * time.Second}, false, "", ConfigSourceLocal); err != nil { + t.Fatalf("err: %s", err) + } + check, ok := a.State.Checks()["service:redis"] + if !ok { + t.Fatalf("missing check") + } + if check.Status != api.HealthPassing { + t.Fatalf("bad: %s", check.Status) + } +} + func TestAgent_NodeMaintenanceMode(t *testing.T) { t.Parallel() a := NewTestAgent(t.Name(), "")