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
No related merge requests found
...@@ -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.
Finish editing this message first!
Please register or to comment