Commit fc6afe2a authored by Matt Holt's avatar Matt Holt

Merge pull request #333 from mholt/firststartup

startup: Only run commands at first startup
parents 51d2ff4e 5cced604
...@@ -71,6 +71,10 @@ var ( ...@@ -71,6 +71,10 @@ var (
// index in the list of inherited file descriptors. This // index in the list of inherited file descriptors. This
// variable is not safe for concurrent access. // variable is not safe for concurrent access.
loadedGob caddyfileGob loadedGob caddyfileGob
// startedBefore should be set to true if caddy has been
// started at least once.
startedBefore bool
) )
const ( const (
...@@ -128,6 +132,7 @@ func Start(cdyfile Input) (err error) { ...@@ -128,6 +132,7 @@ func Start(cdyfile Input) (err error) {
if err != nil { if err != nil {
return err return err
} }
startedBefore = true
// Close remaining file descriptors we may have inherited that we don't need // Close remaining file descriptors we may have inherited that we don't need
if IsRestart() { if IsRestart() {
...@@ -203,6 +208,18 @@ func startServers(groupings bindingGroup) error { ...@@ -203,6 +208,18 @@ func startServers(groupings bindingGroup) error {
wg.Add(1) wg.Add(1)
go func(s *server.Server, ln server.ListenerFile) { go func(s *server.Server, ln server.ListenerFile) {
defer wg.Done() defer wg.Done()
// run startup functions that should only execute when
// the original parent process is starting.
if !IsRestart() && !startedBefore {
err := s.RunFirstStartupFuncs()
if err != nil {
errChan <- err
return
}
}
// start the server
if ln != nil { if ln != nil {
errChan <- s.Serve(ln) errChan <- s.Serve(ln)
} else { } else {
......
...@@ -10,7 +10,7 @@ import ( ...@@ -10,7 +10,7 @@ import (
// Startup registers a startup callback to execute during server start. // Startup registers a startup callback to execute during server start.
func Startup(c *Controller) (middleware.Middleware, error) { func Startup(c *Controller) (middleware.Middleware, error) {
return nil, registerCallback(c, &c.Startup) return nil, registerCallback(c, &c.FirstStartup)
} }
// Shutdown registers a shutdown callback to execute during process exit. // Shutdown registers a shutdown callback to execute during process exit.
......
...@@ -45,7 +45,7 @@ func TestStartup(t *testing.T) { ...@@ -45,7 +45,7 @@ func TestStartup(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Expected no errors, got: %v", err) t.Errorf("Expected no errors, got: %v", err)
} }
err = c.Startup[0]() err = c.FirstStartup[0]()
if err != nil && !test.shouldExecutionErr { if err != nil && !test.shouldExecutionErr {
t.Errorf("Test %d recieved an error of:\n%v", i, err) t.Errorf("Test %d recieved an error of:\n%v", i, err)
} }
......
...@@ -26,11 +26,21 @@ type Config struct { ...@@ -26,11 +26,21 @@ type Config struct {
// Middleware stack; map of path scope to middleware -- TODO: Support path scope? // Middleware stack; map of path scope to middleware -- TODO: Support path scope?
Middleware map[string][]middleware.Middleware Middleware map[string][]middleware.Middleware
// Functions (or methods) to execute at server start; these // Startup is a list of functions (or methods) to execute at
// are executed before any parts of the server are configured, // server startup and restart; these are executed before any
// and the functions are blocking // parts of the server are configured, and the functions are
// blocking. These are good for setting up middlewares and
// starting goroutines.
Startup []func() error Startup []func() error
// FirstStartup is like Startup but these functions only execute
// during the initial startup, not on subsequent restarts.
//
// (Note: The server does not ever run these on its own; it is up
// to the calling application to do so, and do so only once, as the
// server itself has no notion whether it's a restart or not.)
FirstStartup []func() error
// Functions (or methods) to execute when the server quits; // Functions (or methods) to execute when the server quits;
// these are executed in response to SIGINT and are blocking // these are executed in response to SIGINT and are blocking
Shutdown []func() error Shutdown []func() error
......
...@@ -371,6 +371,23 @@ func setupClientAuth(tlsConfigs []TLSConfig, config *tls.Config) error { ...@@ -371,6 +371,23 @@ func setupClientAuth(tlsConfigs []TLSConfig, config *tls.Config) error {
return nil return nil
} }
// RunFirstStartupFuncs runs all of the server's FirstStartup
// callback functions unless one of them returns an error first.
// It is up the caller's responsibility to call this only once and
// at the correct time. The functions here should not be executed
// at restarts or where the user does not explicitly start a new
// instance of the server.
func (s *Server) RunFirstStartupFuncs() error {
for _, vh := range s.vhosts {
for _, f := range vh.config.FirstStartup {
if err := f(); err != nil {
return err
}
}
}
return nil
}
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted // tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so // connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually // dead TCP connections (e.g. closing laptop mid-download) eventually
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment