Skip to content
Snippets Groups Projects
Commit 0d74cd9a authored by ale's avatar ale
Browse files

Improve robustness of update canceling

Also prevents update goroutines from piling up if they are delayed by
adding a semaphore in startUpdate().
parent d262436f
No related branches found
No related tags found
No related merge requests found
...@@ -249,12 +249,23 @@ func (m *Manager) loop(ctx context.Context) { ...@@ -249,12 +249,23 @@ func (m *Manager) loop(ctx context.Context) {
// Updates are long-term jobs, so they should be // Updates are long-term jobs, so they should be
// interruptible. We run updates in a separate goroutine, and // interruptible. We run updates in a separate goroutine, and
// cancel them when the configuration is reloaded or on exit. // cancel them when the configuration is reloaded or on exit.
// A simple channel is used as a semaphore, so that only one
// update goroutine can be running at any given time (without
// other ones piling up).
var upCancel context.CancelFunc var upCancel context.CancelFunc
var wg sync.WaitGroup var wg sync.WaitGroup
sem := make(chan struct{}, 1)
startUpdate := func(certs []*certInfo) context.CancelFunc { startUpdate := func(certs []*certInfo) context.CancelFunc {
// Ensure the previous update has finished. // Acquire the semaphore, return if we fail to.
wg.Wait() select {
case sem <- struct{}{}:
default:
return nil
}
defer func() {
<-sem
}()
upCtx, cancel := context.WithCancel(ctx) upCtx, cancel := context.WithCancel(ctx)
wg.Add(1) wg.Add(1)
...@@ -270,6 +281,7 @@ func (m *Manager) loop(ctx context.Context) { ...@@ -270,6 +281,7 @@ func (m *Manager) loop(ctx context.Context) {
cancelUpdate := func() { cancelUpdate := func() {
if upCancel != nil { if upCancel != nil {
upCancel() upCancel()
upCancel = nil
} }
wg.Wait() wg.Wait()
} }
...@@ -278,17 +290,21 @@ func (m *Manager) loop(ctx context.Context) { ...@@ -278,17 +290,21 @@ func (m *Manager) loop(ctx context.Context) {
tick := time.NewTicker(5 * time.Minute) tick := time.NewTicker(5 * time.Minute)
defer tick.Stop() defer tick.Stop()
for { for {
var c func()
select { select {
case <-tick.C: case <-tick.C:
upCancel = startUpdate(m.certs) c = startUpdate(m.certs)
case <-testUpdateCh: case <-testUpdateCh:
upCancel = startUpdate(m.certs) c = startUpdate(m.certs)
case certDomains := <-m.configCh: case certDomains := <-m.configCh:
cancelUpdate() cancelUpdate()
m.certs = m.loadConfig(certDomains) m.certs = m.loadConfig(certDomains)
case <-ctx.Done(): case <-ctx.Done():
return return
} }
if c != nil {
upCancel = nil
}
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment