summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2021-08-03 16:40:33 -0600
committerBrian Picciano <mediocregopher@gmail.com>2021-08-03 16:40:33 -0600
commit8ebf4a26f46867dbc76e2dc35aab0a6dad25afc5 (patch)
tree7e5d74e21e2982e5711e927e193c509a137d2f2a
parent9c3ea8dd803d6f0df768e3ae37f8c4ab2efbcc5c (diff)
gracefully shutdown on sigint/sigterm
-rw-r--r--srv/cmd/mediocre-blog/main.go65
1 files changed, 52 insertions, 13 deletions
diff --git a/srv/cmd/mediocre-blog/main.go b/srv/cmd/mediocre-blog/main.go
index b94d405..f912f45 100644
--- a/srv/cmd/mediocre-blog/main.go
+++ b/srv/cmd/mediocre-blog/main.go
@@ -2,14 +2,20 @@ package main
import (
"context"
+ "errors"
"flag"
"fmt"
+ "net"
"net/http"
"net/http/httputil"
"net/url"
+ "os"
+ "os/signal"
"path"
"strconv"
"strings"
+ "syscall"
+ "time"
"github.com/emersion/go-sasl"
"github.com/mediocregopher/blog.mediocregopher.com/srv/mailinglist"
@@ -25,10 +31,17 @@ func loggerFatalErr(ctx context.Context, logger *mlog.Logger, descr string, err
func main() {
+ ctx := context.Background()
+
logger := mlog.NewLogger(nil)
+ defer logger.Close()
+
+ logger.Info(ctx, "process started")
+ defer logger.Info(ctx, "process exiting")
publicURLStr := flag.String("public-url", "http://localhost:4000", "URL this service is accessible at")
- listenAddr := flag.String("listen-addr", ":4000", "Address to listen for HTTP requests on")
+ listenProto := flag.String("listen-proto", "tcp", "Protocol to listen for HTTP requests with")
+ listenAddr := flag.String("listen-addr", ":4000", "Address/path to listen for HTTP requests on")
dataDir := flag.String("data-dir", ".", "Directory to use for long term storage")
staticDir := flag.String("static-dir", "", "Directory from which static files are served (mutually exclusive with -static-proxy-url)")
@@ -46,45 +59,46 @@ func main() {
switch {
case *staticDir == "" && *staticProxyURLStr == "":
- logger.Fatal(context.Background(), "-static-dir or -static-proxy-url is required")
+ logger.Fatal(ctx, "-static-dir or -static-proxy-url is required")
case *powSecret == "":
- logger.Fatal(context.Background(), "-pow-secret is required")
+ logger.Fatal(ctx, "-pow-secret is required")
case *smtpAddr == "":
- logger.Fatal(context.Background(), "-ml-smtp-addr is required")
+ logger.Fatal(ctx, "-ml-smtp-addr is required")
case *smtpAuthStr == "":
- logger.Fatal(context.Background(), "-ml-smtp-auth is required")
+ logger.Fatal(ctx, "-ml-smtp-auth is required")
}
publicURL, err := url.Parse(*publicURLStr)
if err != nil {
- loggerFatalErr(context.Background(), logger, "parsing -public-url", err)
+ loggerFatalErr(ctx, logger, "parsing -public-url", err)
}
var staticProxyURL *url.URL
if *staticProxyURLStr != "" {
var err error
if staticProxyURL, err = url.Parse(*staticProxyURLStr); err != nil {
- loggerFatalErr(context.Background(), logger, "parsing -static-proxy-url", err)
+ loggerFatalErr(ctx, logger, "parsing -static-proxy-url", err)
}
}
powTargetUint, err := strconv.ParseUint(*powTargetStr, 0, 32)
if err != nil {
- loggerFatalErr(context.Background(), logger, "parsing -pow-target", err)
+ loggerFatalErr(ctx, logger, "parsing -pow-target", err)
}
powTarget := uint32(powTargetUint)
smtpAuthParts := strings.SplitN(*smtpAuthStr, ":", 2)
if len(smtpAuthParts) < 2 {
- logger.Fatal(context.Background(), "invalid -ml-smtp-auth")
+ logger.Fatal(ctx, "invalid -ml-smtp-auth")
}
smtpAuth := sasl.NewPlainClient("", smtpAuthParts[0], smtpAuthParts[1])
smtpSendAs := smtpAuthParts[0]
// initialization
- ctx := mctx.Annotate(context.Background(),
+ ctx = mctx.Annotate(ctx,
"publicURL", publicURL.String(),
+ "listenProto", *listenProto,
"listenAddr", *listenAddr,
"dataDir", *dataDir,
"powTarget", fmt.Sprintf("%x", powTarget),
@@ -164,7 +178,32 @@ func main() {
logger.Info(ctx, "listening")
- // TODO graceful shutdown
- err = http.ListenAndServe(*listenAddr, mux)
- loggerFatalErr(ctx, logger, "listening", err)
+ l, err := net.Listen(*listenProto, *listenAddr)
+ if err != nil {
+ loggerFatalErr(ctx, logger, "creating listen socket", err)
+ }
+
+ srv := &http.Server{Handler: mux}
+ go func() {
+ if err := srv.Serve(l); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ loggerFatalErr(ctx, logger, "serving http server", err)
+ }
+ }()
+
+ defer func() {
+ closeCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
+ defer cancel()
+
+ logger.Info(ctx, "beginning graceful shutdown of http server")
+
+ if err := srv.Shutdown(closeCtx); err != nil {
+ loggerFatalErr(ctx, logger, "gracefully shutting down http server", err)
+ }
+ }()
+
+ sigCh := make(chan os.Signal)
+ signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
+ <-sigCh
+
+ // let the defers begin
}