Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ra: wait for validations on clean shutdown #7854

Merged
merged 1 commit into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/boulder-ra/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ func main() {
apc,
issuerCerts,
)
defer rai.DrainFinalize()
defer rai.Drain()

policyErr := rai.LoadRateLimitPoliciesFile(c.RA.RateLimitPoliciesFilename)
cmd.FailOnError(policyErr, "Couldn't load rate limit policies file")
Expand Down
20 changes: 15 additions & 5 deletions ra/ra.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ type RegistrationAuthorityImpl struct {
maxNames int
orderLifetime time.Duration
finalizeTimeout time.Duration
finalizeWG sync.WaitGroup
drainWG sync.WaitGroup

issuersByNameID map[issuance.NameID]*issuance.Certificate
purger akamaipb.AkamaiPurgerClient
Expand Down Expand Up @@ -1010,15 +1010,15 @@ func (ra *RegistrationAuthorityImpl) FinalizeOrder(ctx context.Context, req *rap
//
// We track this goroutine's lifetime in a waitgroup global to this RA, so
// that it can wait for all goroutines to drain during shutdown.
ra.finalizeWG.Add(1)
ra.drainWG.Add(1)
go func() {
_, err := ra.issueCertificateOuter(ctx, proto.Clone(order).(*corepb.Order), csr, logEvent)
if err != nil {
// We only log here, because this is in a background goroutine with
// no parent goroutine waiting for it to receive the error.
ra.log.AuditErrf("Asynchronous finalization failed: %s", err.Error())
}
ra.finalizeWG.Done()
ra.drainWG.Done()
}()
return order, nil
} else {
Expand Down Expand Up @@ -1904,8 +1904,11 @@ func (ra *RegistrationAuthorityImpl) PerformValidation(
}

// Dispatch to the VA for service
ra.drainWG.Add(1)
vaCtx := context.Background()
go func(authz core.Authorization) {
defer ra.drainWG.Done()

// We will mutate challenges later in this goroutine to change status and
// add error, but we also return a copy of authz immediately. To avoid a
// data race, make a copy of the challenges slice here for mutation.
Expand Down Expand Up @@ -2803,6 +2806,13 @@ func (ra *RegistrationAuthorityImpl) GetAuthorization(ctx context.Context, req *
return authz, nil
}

func (ra *RegistrationAuthorityImpl) DrainFinalize() {
ra.finalizeWG.Wait()
// Drain blocks until all detached goroutines are done.
//
// The RA runs detached goroutines for challenge validation and finalization,
// so that ACME responses can be returned to the user promptly while work continues.
//
// The main goroutine should call this before exiting to avoid canceling the work
// being done in detached goroutines.
func (ra *RegistrationAuthorityImpl) Drain() {
ra.drainWG.Wait()
}
Loading