Skip to content
Snippets Groups Projects
Commit 78598be6 authored by ale's avatar ale
Browse files

Make updates interruptible

parent 9afc1865
No related branches found
No related tags found
Loading
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
"io" "io"
"log" "log"
"path/filepath" "path/filepath"
"sync"
"time" "time"
"git.autistici.org/ai3/go-common/clientutil" "git.autistici.org/ai3/go-common/clientutil"
...@@ -126,11 +127,19 @@ var ( ...@@ -126,11 +127,19 @@ var (
errorRetryTimeout = 10 * time.Minute errorRetryTimeout = 10 * time.Minute
) )
func (m *Manager) updateAllCerts(ctx context.Context) { func (m *Manager) updateAllCerts(ctx context.Context, certs []*certInfo) {
for _, certInfo := range m.certs { for _, certInfo := range certs {
if certInfo.retryDeadline.After(time.Now()) { if certInfo.retryDeadline.After(time.Now()) {
continue continue
} }
// Abort the loop if our context is canceled.
select {
case <-ctx.Done():
return
default:
}
uctx, cancel := context.WithTimeout(ctx, renewalTimeout) uctx, cancel := context.WithTimeout(ctx, renewalTimeout)
err := m.updateCert(uctx, certInfo) err := m.updateCert(uctx, certInfo)
cancel() cancel()
...@@ -174,7 +183,7 @@ func (m *Manager) updateCert(ctx context.Context, certInfo *certInfo) error { ...@@ -174,7 +183,7 @@ func (m *Manager) updateCert(ctx context.Context, certInfo *certInfo) error {
} }
// Replace the current configuration. // Replace the current configuration.
func (m *Manager) loadConfig(certDomains [][]string) { func (m *Manager) loadConfig(certDomains [][]string) []*certInfo {
var certs []*certInfo var certs []*certInfo
for _, domains := range certDomains { for _, domains := range certDomains {
cn := domains[0] cn := domains[0]
...@@ -197,7 +206,7 @@ func (m *Manager) loadConfig(certDomains [][]string) { ...@@ -197,7 +206,7 @@ func (m *Manager) loadConfig(certDomains [][]string) {
} }
certs = append(certs, certInfo) certs = append(certs, certInfo)
} }
m.certs = certs return certs
} }
// This channel is used by the testing code to trigger an update, // This channel is used by the testing code to trigger an update,
...@@ -205,15 +214,43 @@ func (m *Manager) loadConfig(certDomains [][]string) { ...@@ -205,15 +214,43 @@ func (m *Manager) loadConfig(certDomains [][]string) {
var testUpdateCh = make(chan bool) var testUpdateCh = make(chan bool)
func (m *Manager) loop(ctx context.Context) { func (m *Manager) loop(ctx context.Context) {
// Updates are long-term jobs, so they should be
// interruptible. We run updates in a separate goroutine, and
// cancel them when the configuration is reloaded or on exit.
var upCancel context.CancelFunc
var wg sync.WaitGroup
startUpdate := func(certs []*certInfo) context.CancelFunc {
// Ensure the previous update has finished.
wg.Wait()
upCtx, cancel := context.WithCancel(ctx)
wg.Add(1)
go func() {
m.updateAllCerts(upCtx, certs)
wg.Done()
}()
return cancel
}
cancelUpdate := func() {
if upCancel != nil {
upCancel()
}
wg.Wait()
}
defer cancelUpdate()
tick := time.NewTicker(5 * time.Minute) tick := time.NewTicker(5 * time.Minute)
for { for {
select { select {
case <-tick.C: case <-tick.C:
m.updateAllCerts(ctx) upCancel = startUpdate(m.certs)
case <-testUpdateCh: case <-testUpdateCh:
m.updateAllCerts(ctx) upCancel = startUpdate(m.certs)
case certDomains := <-m.configCh: case certDomains := <-m.configCh:
m.loadConfig(certDomains) cancelUpdate()
m.certs = m.loadConfig(certDomains)
case <-m.stopCh: case <-m.stopCh:
return return
case <-ctx.Done(): case <-ctx.Done():
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment