diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index d25951b93..01dbb9ed2 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -188,7 +188,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err return nil, err } - acmeProviders := initACMEProvider(staticConfiguration, providerAggregator, tlsManager, httpChallengeProvider, tlsChallengeProvider) + acmeProviders := initACMEProvider(staticConfiguration, providerAggregator, tlsManager, httpChallengeProvider, tlsChallengeProvider, routinesPool) // Entrypoints @@ -366,7 +366,7 @@ func switchRouter(routerFactory *server.RouterFactory, serverEntryPointsTCP serv } // initACMEProvider creates an acme provider from the ACME part of globalConfiguration. -func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager, httpChallengeProvider, tlsChallengeProvider challenge.Provider) []*acme.Provider { +func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager, httpChallengeProvider, tlsChallengeProvider challenge.Provider, routinesPool *safe.Pool) []*acme.Provider { localStores := map[string]*acme.LocalStore{} var resolvers []*acme.Provider @@ -376,7 +376,7 @@ func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.Pr } if localStores[resolver.ACME.Storage] == nil { - localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage) + localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage, routinesPool) } p := &acme.Provider{ diff --git a/pkg/provider/acme/local_store.go b/pkg/provider/acme/local_store.go index 33084b320..9a75c704e 100644 --- a/pkg/provider/acme/local_store.go +++ b/pkg/provider/acme/local_store.go @@ -1,6 +1,7 @@ package acme import ( + "context" "encoding/json" "io" "os" @@ -22,9 +23,9 @@ type LocalStore struct { } // NewLocalStore initializes a new LocalStore with a file name. -func NewLocalStore(filename string) *LocalStore { +func NewLocalStore(filename string, routinesPool *safe.Pool) *LocalStore { store := &LocalStore{filename: filename, saveDataChan: make(chan map[string]*StoredData)} - store.listenSaveAction() + store.listenSaveAction(routinesPool) return store } @@ -99,18 +100,31 @@ func (s *LocalStore) get(resolverName string) (*StoredData, error) { } // listenSaveAction listens to a chan to store ACME data in json format into `LocalStore.filename`. -func (s *LocalStore) listenSaveAction() { - safe.Go(func() { +func (s *LocalStore) listenSaveAction(routinesPool *safe.Pool) { + routinesPool.GoCtx(func(ctx context.Context) { logger := log.WithoutContext().WithField(log.ProviderName, "acme") - for object := range s.saveDataChan { - data, err := json.MarshalIndent(object, "", " ") - if err != nil { - logger.Error(err) - } + for { + select { + case <-ctx.Done(): + return - err = os.WriteFile(s.filename, data, 0o600) - if err != nil { - logger.Error(err) + case object := <-s.saveDataChan: + select { + case <-ctx.Done(): + // Stop handling events because Traefik is shutting down. + return + default: + } + + data, err := json.MarshalIndent(object, "", " ") + if err != nil { + logger.Error(err) + } + + err = os.WriteFile(s.filename, data, 0o600) + if err != nil { + logger.Error(err) + } } } }) diff --git a/pkg/provider/acme/local_store_test.go b/pkg/provider/acme/local_store_test.go index 4614078c0..61d2cff6b 100644 --- a/pkg/provider/acme/local_store_test.go +++ b/pkg/provider/acme/local_store_test.go @@ -1,6 +1,7 @@ package acme import ( + "context" "fmt" "os" "path/filepath" @@ -9,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/traefik/traefik/v2/pkg/safe" ) func TestLocalStore_GetAccount(t *testing.T) { @@ -45,7 +47,7 @@ func TestLocalStore_GetAccount(t *testing.T) { for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { - s := NewLocalStore(test.filename) + s := NewLocalStore(test.filename, safe.NewPool(context.Background())) account, err := s.GetAccount("test") require.NoError(t, err) @@ -58,7 +60,7 @@ func TestLocalStore_GetAccount(t *testing.T) { func TestLocalStore_SaveAccount(t *testing.T) { acmeFile := filepath.Join(t.TempDir(), "acme.json") - s := NewLocalStore(acmeFile) + s := NewLocalStore(acmeFile, safe.NewPool(context.Background())) email := "some@email.com"