Fix scheduler cleanup edge cases
This commit is contained in:
@@ -217,7 +217,7 @@ func (c *Config) Validate() error {
|
|||||||
return fmt.Errorf("check %q: timeout must be > 0", ch.ID)
|
return fmt.Errorf("check %q: timeout must be > 0", ch.ID)
|
||||||
}
|
}
|
||||||
if ch.Interval.Duration < 0 {
|
if ch.Interval.Duration < 0 {
|
||||||
return fmt.Errorf("check %q: interval must be > 0", ch.ID)
|
return fmt.Errorf("check %q: interval must not be negative", ch.ID)
|
||||||
}
|
}
|
||||||
ch.Cron = strings.TrimSpace(ch.Cron)
|
ch.Cron = strings.TrimSpace(ch.Cron)
|
||||||
hasInterval := ch.Interval.Duration > 0
|
hasInterval := ch.Interval.Duration > 0
|
||||||
|
|||||||
@@ -123,6 +123,29 @@ func TestValidateCheckScheduleChoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateNegativeIntervalMessage(t *testing.T) {
|
||||||
|
_, err := Load(writeTmp(t, `
|
||||||
|
agent_id = "host-1"
|
||||||
|
state_dir = "/tmp/x"
|
||||||
|
|
||||||
|
[server]
|
||||||
|
enabled = true
|
||||||
|
url = "http://localhost"
|
||||||
|
|
||||||
|
[[checks]]
|
||||||
|
id = "c1"
|
||||||
|
command = "true"
|
||||||
|
interval = "-1s"
|
||||||
|
timeout = "5s"
|
||||||
|
`))
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected negative interval error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "interval must not be negative") {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadResourceLimits(t *testing.T) {
|
func TestLoadResourceLimits(t *testing.T) {
|
||||||
c, err := Load(writeTmp(t, `
|
c, err := Load(writeTmp(t, `
|
||||||
agent_id = "host-1"
|
agent_id = "host-1"
|
||||||
|
|||||||
@@ -202,13 +202,24 @@ func (w *checkWorker) Wait() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *checkWorker) loop(initial config.CheckConfig) {
|
func (w *checkWorker) loop(initial config.CheckConfig) {
|
||||||
|
cfg := initial
|
||||||
|
stoppedNotified := false
|
||||||
|
notifyStopped := func() {
|
||||||
|
if stoppedNotified {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stoppedNotified = true
|
||||||
|
if w.hooks.OnStopped != nil {
|
||||||
|
w.hooks.OnStopped(cfg.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
|
notifyStopped()
|
||||||
if w.onDone != nil {
|
if w.onDone != nil {
|
||||||
w.onDone(w)
|
w.onDone(w)
|
||||||
}
|
}
|
||||||
w.wg.Done()
|
w.wg.Done()
|
||||||
}()
|
}()
|
||||||
cfg := initial
|
|
||||||
t := time.NewTimer(time.Hour)
|
t := time.NewTimer(time.Hour)
|
||||||
stopTimer(t)
|
stopTimer(t)
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
@@ -249,9 +260,6 @@ func (w *checkWorker) loop(initial config.CheckConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !arm(cfg, true) {
|
if !arm(cfg, true) {
|
||||||
if w.hooks.OnStopped != nil {
|
|
||||||
w.hooks.OnStopped(cfg.ID)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,18 +269,12 @@ func (w *checkWorker) loop(initial config.CheckConfig) {
|
|||||||
stopping = true
|
stopping = true
|
||||||
ctxDone = nil
|
ctxDone = nil
|
||||||
if !running {
|
if !running {
|
||||||
if w.hooks.OnStopped != nil {
|
|
||||||
w.hooks.OnStopped(cfg.ID)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case <-stopCh:
|
case <-stopCh:
|
||||||
stopping = true
|
stopping = true
|
||||||
stopCh = nil
|
stopCh = nil
|
||||||
if !running {
|
if !running {
|
||||||
if w.hooks.OnStopped != nil {
|
|
||||||
w.hooks.OnStopped(cfg.ID)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case next := <-w.updateCh:
|
case next := <-w.updateCh:
|
||||||
@@ -307,9 +309,6 @@ func (w *checkWorker) loop(initial config.CheckConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if stopping {
|
if stopping {
|
||||||
if w.hooks.OnStopped != nil {
|
|
||||||
w.hooks.OnStopped(cfg.ID)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if runAfterCurrent {
|
if runAfterCurrent {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package scheduler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -107,6 +108,38 @@ func TestCronEmitsOnDueSlot(t *testing.T) {
|
|||||||
m.Wait()
|
m.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCronArmErrorCallsStoppedHook(t *testing.T) {
|
||||||
|
old := parseCronSchedule
|
||||||
|
var calls int32
|
||||||
|
parseCronSchedule = func(string) (cron.Schedule, error) {
|
||||||
|
if atomic.AddInt32(&calls, 1) == 1 {
|
||||||
|
return fakeCronSchedule{delay: 10 * time.Millisecond}, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("boom")
|
||||||
|
}
|
||||||
|
t.Cleanup(func() { parseCronSchedule = old })
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
|
defer cancel()
|
||||||
|
out := make(chan Event, 10)
|
||||||
|
stopped := make(chan string, 1)
|
||||||
|
m := NewManager(ctx, "a1", out, Hooks{
|
||||||
|
OnStopped: func(id string) { stopped <- id },
|
||||||
|
})
|
||||||
|
m.Update([]config.CheckConfig{mkCronCheck("cron", "true", 100*time.Millisecond)})
|
||||||
|
|
||||||
|
select {
|
||||||
|
case id := <-stopped:
|
||||||
|
if id != "cron" {
|
||||||
|
t.Fatalf("unexpected stopped id: %q", id)
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
t.Fatal("stopped hook was not called")
|
||||||
|
}
|
||||||
|
m.Stop()
|
||||||
|
m.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
func TestNoOverlapSkips(t *testing.T) {
|
func TestNoOverlapSkips(t *testing.T) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 600*time.Millisecond)
|
ctx, cancel := context.WithTimeout(context.Background(), 600*time.Millisecond)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|||||||
@@ -13,12 +13,6 @@
|
|||||||
--font-mono: var(--font-geist-mono);
|
--font-mono: var(--font-geist-mono);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-theme="dark"] {
|
|
||||||
--background: #0a0a0a;
|
|
||||||
--foreground: #ededed;
|
|
||||||
color-scheme: dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
|
|||||||
Reference in New Issue
Block a user