Keep working out the home page cards after startup (closes #211)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Server.Start ran the loop that works out the home page's cards on the context it was given. fx ends that context once start-up is done, so the cards were worked out once and never again. The loop now runs on a context that only Stop ends, as the other background parts do. Stop waits for the loop to return, until its own context ends, before it stops the HTTP server. A new test starts a server in a synctest bubble and ends its context at once. On the bubble's fake clock, the cards must be worked out again a minute later, and not after Stop. Model: opus-5-5
This commit was merged in pull request #212.
This commit is contained in:
@@ -82,6 +82,12 @@ type Server struct {
|
||||
// cards is the copy of the home page's cards that the pages serve, nil
|
||||
// until the server first works them out
|
||||
cards atomic.Pointer[homeCards]
|
||||
|
||||
// stopCards ends the goroutine that works out the cards, and
|
||||
// cardsStopped is closed once it has returned. Both are nil until Start
|
||||
// starts the goroutine.
|
||||
stopCards context.CancelFunc
|
||||
cardsStopped chan struct{}
|
||||
}
|
||||
|
||||
// New creates a new HTTP server that reads routes from table, the routing
|
||||
@@ -111,7 +117,8 @@ func New(
|
||||
// Start listens on the configured port and serves HTTP in the background.
|
||||
// It returns an error if it cannot listen, for example because the port is
|
||||
// already in use. ctx bounds opening the port, not serving. Once listening,
|
||||
// the server works out the home page's cards every minute until ctx ends.
|
||||
// the server works out the home page's cards every minute until Stop: the end
|
||||
// of ctx does not stop it.
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
const (
|
||||
network = "tcp"
|
||||
@@ -148,16 +155,22 @@ func (s *Server) Start(ctx context.Context) error {
|
||||
}
|
||||
}()
|
||||
|
||||
ctx, s.stopCards = context.WithCancel(context.WithoutCancel(ctx))
|
||||
s.cardsStopped = make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(s.cardsStopped)
|
||||
|
||||
s.keepHomeCardsFresh(ctx, homeCardsRefreshInterval)
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the HTTP server. It waits, until ctx ends, for the requests in
|
||||
// progress to finish, and then closes the connections of those still running
|
||||
// and returns ctx's error.
|
||||
// Stop stops the goroutine that works out the home page's cards, and waits
|
||||
// until it has returned or ctx ends. It then stops the HTTP server. It waits,
|
||||
// until ctx ends, for the requests in progress to finish, and then closes the
|
||||
// connections of those still running and returns ctx's error.
|
||||
func (s *Server) Stop(ctx context.Context) error {
|
||||
if s.srv == nil {
|
||||
return nil
|
||||
@@ -165,6 +178,16 @@ func (s *Server) Stop(ctx context.Context) error {
|
||||
|
||||
s.logger.Info("Stopping HTTP server")
|
||||
|
||||
// Start returns before it starts the goroutine when it cannot listen.
|
||||
if s.stopCards != nil {
|
||||
s.stopCards()
|
||||
|
||||
select {
|
||||
case <-s.cardsStopped:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
|
||||
err := s.srv.Shutdown(ctx)
|
||||
if err != nil {
|
||||
return errors.Join(err, s.srv.Close())
|
||||
|
||||
Reference in New Issue
Block a user