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 (
"io"
"log"
"path/filepath"
"sync"
"time"
"git.autistici.org/ai3/go-common/clientutil"
......@@ -126,11 +127,19 @@ var (
errorRetryTimeout = 10 * time.Minute
)
func (m *Manager) updateAllCerts(ctx context.Context) {
for _, certInfo := range m.certs {
func (m *Manager) updateAllCerts(ctx context.Context, certs []*certInfo) {
for _, certInfo := range certs {
if certInfo.retryDeadline.After(time.Now()) {
continue
}
// Abort the loop if our context is canceled.
select {
case <-ctx.Done():
return
default:
}
uctx, cancel := context.WithTimeout(ctx, renewalTimeout)
err := m.updateCert(uctx, certInfo)
cancel()
......@@ -174,7 +183,7 @@ func (m *Manager) updateCert(ctx context.Context, certInfo *certInfo) error {
}
// Replace the current configuration.
func (m *Manager) loadConfig(certDomains [][]string) {
func (m *Manager) loadConfig(certDomains [][]string) []*certInfo {
var certs []*certInfo
for _, domains := range certDomains {
cn := domains[0]
......@@ -197,7 +206,7 @@ func (m *Manager) loadConfig(certDomains [][]string) {
}
certs = append(certs, certInfo)
}
m.certs = certs
return certs
}
// This channel is used by the testing code to trigger an update,
......@@ -205,15 +214,43 @@ func (m *Manager) loadConfig(certDomains [][]string) {
var testUpdateCh = make(chan bool)
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)
for {
select {
case <-tick.C:
m.updateAllCerts(ctx)
upCancel = startUpdate(m.certs)
case <-testUpdateCh:
m.updateAllCerts(ctx)
upCancel = startUpdate(m.certs)
case certDomains := <-m.configCh:
m.loadConfig(certDomains)
cancelUpdate()
m.certs = m.loadConfig(certDomains)
case <-m.stopCh:
return
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