Commit 15fa5cf2 authored by Matthew Holt's avatar Matthew Holt

OnFirstStartup and OnFinalShutdown callbacks added

OnStartup and OnShutdown callbacks now run as part of restarts, too.
The startup and shutdown directives only run their commands NOT as part
of restarts, as before. Some middleware that use OnStartup may need to
switch to OnFirstStartup and implement OnFinalShutdown to do any cleanup
as needed.
parent b49f65d5
......@@ -73,10 +73,12 @@ type Instance struct {
// servers is the list of servers with their listeners.
servers []serverListener
// these are callbacks to execute when certain events happen
onStartup []func() error
onRestart []func() error
onShutdown []func() error
// these callbacks execute when certain events occur
onFirstStartup []func() error // starting, not as part of a restart
onStartup []func() error // starting, even as part of a restart
onRestart []func() error // before restart commences
onShutdown []func() error // stopping, even as part of a restart
onFinalShutdown []func() error // stopping, not as part of a restart
}
// Stop stops all servers contained in i. It does NOT
......@@ -104,10 +106,11 @@ func (i *Instance) Stop() error {
return nil
}
// shutdownCallbacks executes all the shutdown callbacks of i.
// An error returned from one does not stop execution of the rest.
// All the errors will be returned.
func (i *Instance) shutdownCallbacks() []error {
// ShutdownCallbacks executes all the shutdown callbacks of i,
// including ones that are scheduled only for the final shutdown
// of i. An error returned from one does not stop execution of
// the rest. All the non-nil errors will be returned.
func (i *Instance) ShutdownCallbacks() []error {
var errs []error
for _, shutdownFunc := range i.onShutdown {
err := shutdownFunc()
......@@ -115,6 +118,12 @@ func (i *Instance) shutdownCallbacks() []error {
errs = append(errs, err)
}
}
for _, finalShutdownFunc := range i.onFinalShutdown {
err := finalShutdownFunc()
if err != nil {
errs = append(errs, err)
}
}
return errs
}
......@@ -159,6 +168,12 @@ func (i *Instance) Restart(newCaddyfile Input) (*Instance, error) {
}
// success! stop the old instance
for _, shutdownFunc := range i.onShutdown {
err := shutdownFunc()
if err != nil {
return i, err
}
}
i.Stop()
log.Println("[INFO] Reloading complete")
......@@ -409,6 +424,15 @@ func startWithListenerFds(cdyfile Input, inst *Instance, restartFds map[string]r
return err
}
// run startup callbacks
if restartFds == nil {
for _, firstStartupFunc := range inst.onFirstStartup {
err := firstStartupFunc()
if err != nil {
return err
}
}
}
for _, startupFunc := range inst.onStartup {
err := startupFunc()
if err != nil {
......
......@@ -29,7 +29,8 @@ type ErrorHandler struct {
LogFile string
Log *log.Logger
LogRoller *httpserver.LogRoller
Debug bool // if true, errors are written out to client rather than to a log
Debug bool // if true, errors are written out to client rather than to a log
file *os.File // a log file to close when done
}
func (h ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
......
......@@ -49,11 +49,10 @@ func setup(c *caddy.Controller) error {
}
if handler.LogRoller != nil {
file.Close()
handler.LogRoller.Filename = handler.LogFile
writer = handler.LogRoller.GetLogWriter()
} else {
handler.file = file
writer = file
}
}
......@@ -62,6 +61,14 @@ func setup(c *caddy.Controller) error {
return nil
})
// When server stops, close any open log file
c.OnShutdown(func() error {
if handler.file != nil {
handler.file.Close()
}
return nil
})
httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
handler.Next = next
return handler
......
......@@ -5,6 +5,7 @@ import (
"fmt"
"log"
"net/http"
"os"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
......@@ -67,6 +68,7 @@ type Rule struct {
Format string
Log *log.Logger
Roller *httpserver.LogRoller
file *os.File // if logging to a file that needs to be closed
}
const (
......
......@@ -43,6 +43,7 @@ func setup(c *caddy.Controller) error {
rules[i].Roller.Filename = rules[i].OutputFile
writer = rules[i].Roller.GetLogWriter()
} else {
rules[i].file = file
writer = file
}
}
......@@ -53,6 +54,16 @@ func setup(c *caddy.Controller) error {
return nil
})
// When server stops, close any open log files
c.OnShutdown(func() error {
for _, rule := range rules {
if rule.file != nil {
rule.file.Close()
}
}
return nil
})
httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
return Logger{Next: next, Rules: rules, ErrorFunc: httpserver.DefaultErrorFunc}
})
......
......@@ -54,8 +54,14 @@ func (c *Controller) ServerType() string {
return c.instance.serverType
}
// OnFirstStartup adds fn to the list of callback functions to execute
// when the server is about to be started NOT as part of a restart.
func (c *Controller) OnFirstStartup(fn func() error) {
c.instance.onFirstStartup = append(c.instance.onFirstStartup, fn)
}
// OnStartup adds fn to the list of callback functions to execute
// when the server is about to be started.
// when the server is about to be started (including restarts).
func (c *Controller) OnStartup(fn func() error) {
c.instance.onStartup = append(c.instance.onStartup, fn)
}
......@@ -67,11 +73,17 @@ func (c *Controller) OnRestart(fn func() error) {
}
// OnShutdown adds fn to the list of callback functions to execute
// when the server is about to be shut down..
// when the server is about to be shut down (including restarts).
func (c *Controller) OnShutdown(fn func() error) {
c.instance.onShutdown = append(c.instance.onShutdown, fn)
}
// OnFinalShutdown adds fn to the list of callback functions to execute
// when the server is about to be shut down NOT as part of a restart.
func (c *Controller) OnFinalShutdown(fn func() error) {
c.instance.onFinalShutdown = append(c.instance.onFinalShutdown, fn)
}
// Context gets the context associated with the instance associated with c.
func (c *Controller) Context() Context {
return c.instance.context
......
......@@ -72,7 +72,7 @@ func allShutdownCallbacks() []error {
var errs []error
instancesMu.Lock()
for _, inst := range instances {
errs = append(errs, inst.shutdownCallbacks()...)
errs = append(errs, inst.ShutdownCallbacks()...)
}
instancesMu.Unlock()
return errs
......
......@@ -15,12 +15,12 @@ func init() {
// Startup registers a startup callback to execute during server start.
func Startup(c *caddy.Controller) error {
return registerCallback(c, c.OnStartup)
return registerCallback(c, c.OnFirstStartup)
}
// Shutdown registers a shutdown callback to execute during server stop.
func Shutdown(c *caddy.Controller) error {
return registerCallback(c, c.OnShutdown)
return registerCallback(c, c.OnFinalShutdown)
}
// registerCallback registers a callback function to execute by
......
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