Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cmd/serve_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ func serve(ctx context.Context) {
defer wg.Wait() // Do not return to caller until this goroutine is done.

mrCache := templatemailer.NewCache()
if !config.Mailer.TemplateReloadingEnabled {
// If template reloading is disabled attempt an initial reload at
// startup for fault tolerance.
wg.Add(1)
go func() {
defer wg.Done()

mrCache.Reload(ctx, config)
}()
}

limiterOpts := api.NewLimiterOptions(config)
initialAPI := api.NewAPIWithVersion(
config, db, utilities.Version,
Expand Down
83 changes: 50 additions & 33 deletions internal/reloader/reloader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,55 +217,62 @@ func TestWatchNotify(t *testing.T) {
})

t.Run("ErrorChanClosed", func(t *testing.T) {
dir, cleanup := helpTestDir(t)
defer cleanup()
fn := func() string {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

cfg := e2e.Must(e2e.Config()).Reloading
cfg.SignalEnabled = false
cfg.PollerEnabled = false
dir, cleanup := helpTestDir(t)
defer cleanup()

rr := mockReloadRecorder()
wr := newMockWatcher(nil)
wr.errorCh <- errors.New("sentinel")
close(wr.errorCh)
cfg := e2e.Must(e2e.Config()).Reloading
cfg.SignalEnabled = false
cfg.PollerEnabled = false

rl := NewReloader(cfg, dir)
rl.watchFn = func() (watcher, error) { return wr, nil }
rr := mockReloadRecorder()
wr := newMockWatcher(nil)
wr.errorCh <- errors.New("sentinel")
close(wr.errorCh)

err := rl.Watch(ctx, rr.configFn)
require.NotNil(t, err)
rl := NewReloader(cfg, dir)
rl.watchFn = func() (watcher, error) { return wr, nil }

msg := "reloader: fsnotify error channel was closed"
if exp, got := msg, err.Error(); exp != got {
require.Equal(t, exp, got)
err := rl.Watch(ctx, rr.configFn)
require.NotNil(t, err)
return err.Error()
}

const exp = "reloader: fsnotify error channel was closed"
runUntilErrorStr(t, exp, fn)
})

t.Run("EventChanClosed", func(t *testing.T) {
dir, cleanup := helpTestDir(t)
defer cleanup()
fn := func() string {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

cfg := e2e.Must(e2e.Config()).Reloading
cfg.SignalEnabled = false
cfg.PollerEnabled = false
cfg.GracePeriodInterval = time.Second / 100
dir, cleanup := helpTestDir(t)
defer cleanup()

rr := mockReloadRecorder()
wr := newMockWatcher(nil)
close(wr.eventCh)
cfg := e2e.Must(e2e.Config()).Reloading
cfg.SignalEnabled = false
cfg.PollerEnabled = false
cfg.GracePeriodInterval = time.Second / 100

rl := NewReloader(cfg, dir)
rl.watchFn = func() (watcher, error) { return wr, nil }
rr := mockReloadRecorder()
wr := newMockWatcher(nil)
close(wr.eventCh)

err := rl.Watch(ctx, rr.configFn)
if err == nil {
rl := NewReloader(cfg, dir)
rl.watchFn = func() (watcher, error) { return wr, nil }

err := rl.Watch(ctx, rr.configFn)
require.NotNil(t, err)
}

msg := "reloader: fsnotify event channel was closed"
if exp, got := msg, err.Error(); exp != got {
require.Equal(t, exp, got)
return err.Error()
}

const exp = "reloader: fsnotify event channel was closed"
runUntilErrorStr(t, exp, fn)
})

t.Run("ErrorChan", func(t *testing.T) {
Expand Down Expand Up @@ -739,6 +746,16 @@ func TestReloadCheckAt(t *testing.T) {
}
}

func runUntilErrorStr(t testing.TB, exp string, fn func() string) {
var got string
for range 100 {
if got = fn(); got == exp {
break
}
}
require.Equal(t, exp, got)
}

func helpTestDir(t testing.TB) (dir string, cleanup func()) {
name := fmt.Sprintf("%v_%v", t.Name(), time.Now().Nanosecond())
dir = filepath.Join("testdata", name)
Expand Down