Skip to content

Commit fc9003b

Browse files
committed
improve graceful shutdown of http server
Update Makefile 'run' to call go run directly on the website. Add HasGitDiff() to ci cmd, to avoid dirty git.
1 parent f9fb841 commit fc9003b

File tree

6 files changed

+86
-55
lines changed

6 files changed

+86
-55
lines changed

Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

2-
CI_CMD := go run ./cmd/ci/*.go
2+
CI_CMD := go run ./cmd/ci/ci.go
3+
WEBSITE_CMD := go run ./cmd/website/website.go
34

45
.PHONY: init
56
init:
@@ -11,7 +12,7 @@ dev:
1112

1213
.PHONY: run
1314
run:
14-
$(CI_CMD) -run
15+
$(WEBSITE_CMD)
1516

1617
.PHONY: pr
1718
pr:

README.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Things you need to install:
4040
To start a local development server:
4141

4242
```bash
43-
go run ./cmd/ci/*.go -dev
43+
make dev
4444

4545
# Open your browser at http://localhost:3000
4646
```
@@ -50,11 +50,9 @@ go run ./cmd/ci/*.go -dev
5050
Before pushing any code changes, make sure that it builds
5151

5252
```bash
53-
go run ./cmd/ci/*.go -pr
53+
make pr
5454
```
5555

56-
> You can preview the built app with `npm run preview`, regardless of whether you installed an adapter. This should _not_ be used to serve your app in production.
57-
5856
## Releasing
5957

6058
Pushing to the `main` branch deploys the changes to the staging environment <https://staging.verifa.io>

TODO.md

-16
This file was deleted.

cmd/ci/ci.go

+24-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"flag"
@@ -48,7 +49,7 @@ const (
4849
var gitCommit = "dev"
4950

5051
func main() {
51-
var dev, build, lint, test, run, preview, pr bool
52+
var dev, build, lint, test, preview, pr bool
5253
var deploy string
5354
flag.BoolVar(&dev, "dev", false, "run the website locally")
5455
flag.BoolVar(&build, "build", false, "build the website locally")
@@ -60,7 +61,6 @@ func main() {
6061
"",
6162
"deploy the website to this env (staging or prod)",
6263
)
63-
flag.BoolVar(&run, "run", false, "run the website locally")
6464
flag.BoolVar(&preview, "preview", false, "run a local preview environment")
6565
flag.BoolVar(&pr, "pr", false, "run the pull request checks")
6666
flag.Parse()
@@ -83,26 +83,24 @@ func main() {
8383
)
8484
defer stop()
8585

86-
if lint {
87-
Lint(ctx)
88-
}
89-
if test {
90-
Test(ctx)
91-
}
9286
if dev {
9387
Dev(ctx)
9488
}
95-
if run {
96-
Run(ctx)
97-
}
9889
if build {
9990
_ = KoBuild(ctx, WithKoLocal())
10091
}
10192
if preview {
10293
Preview(ctx)
10394
}
95+
if lint {
96+
Lint(ctx)
97+
}
98+
if test {
99+
Test(ctx)
100+
}
104101
if pr {
105102
PullRequest(ctx)
103+
HasGitDiff(ctx)
106104
}
107105
if deploy != "" {
108106
Deploy(ctx, deploy)
@@ -115,11 +113,6 @@ func Dev(ctx context.Context) {
115113
<-ctx.Done()
116114
}
117115

118-
func Run(ctx context.Context) {
119-
iferr(Generate(ctx))
120-
iferr(Go(ctx, "run", "./cmd/website/main.go"))
121-
}
122-
123116
func Watch(ctx context.Context) {
124117
fmt.Println("👀 watching for changes")
125118

@@ -308,6 +301,21 @@ func PullRequest(ctx context.Context) {
308301
fmt.Println("✅ pull request checks passed")
309302
}
310303

304+
// HasGitDiff displays the git diff and errors if there is a diff
305+
func HasGitDiff(ctx context.Context) {
306+
cmd := exec.CommandContext(ctx, "git", "--no-pager", "diff")
307+
slog.Info("exec", slog.String("cmd", cmd.String()))
308+
b, err := cmd.CombinedOutput()
309+
iferr(err)
310+
if len(b) == 0 {
311+
return
312+
}
313+
buf := bytes.NewBuffer(b)
314+
fmt.Println("❌ git diff is not empty:")
315+
fmt.Println(buf.String())
316+
os.Exit(1)
317+
}
318+
311319
func Deploy(ctx context.Context, deploy string) {
312320
var cloudRunService string
313321
switch deploy {

cmd/website/website.go

+19-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package main
22

33
import (
4+
"context"
45
"flag"
56
"log/slog"
67
"os"
8+
"os/signal"
79

810
"github.com/verifa/website"
911
)
1012

11-
var buildGitCommit = "dev"
13+
var (
14+
buildGitCommit = "dev"
15+
isProduction bool
16+
)
1217

1318
func main() {
14-
var isProduction bool
1519
flag.BoolVar(
1620
&isProduction,
1721
"prod",
@@ -20,11 +24,21 @@ func main() {
2024
)
2125
flag.Parse()
2226

23-
if err := website.Run(website.Site{
27+
if err := run(); err != nil {
28+
slog.Error("running website", "error", err)
29+
os.Exit(1)
30+
}
31+
}
32+
33+
func run() error {
34+
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
35+
defer cancel()
36+
37+
if err := website.Run(ctx, website.Site{
2438
Commit: buildGitCommit,
2539
IsProduction: isProduction,
2640
}); err != nil {
27-
slog.Error("starting website", "error", err)
28-
os.Exit(1)
41+
return err
2942
}
43+
return nil
3044
}

server.go

+38-12
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package website
22

33
import (
4+
"context"
45
"crypto/md5"
56
"embed"
67
"encoding/hex"
8+
"errors"
79
"fmt"
810
"io/fs"
911
"log/slog"
@@ -13,6 +15,7 @@ import (
1315
"net/url"
1416
"path/filepath"
1517
"strings"
18+
"sync"
1619
"time"
1720

1821
"github.com/go-chi/chi/v5"
@@ -48,14 +51,7 @@ type Site struct {
4851
IsProduction bool
4952
}
5053

51-
func Run(site Site) error {
52-
slog.Info(
53-
"starting website",
54-
"commit",
55-
site.Commit,
56-
"production",
57-
site.IsProduction,
58-
)
54+
func Run(ctx context.Context, site Site) error {
5955
// Parse posts.
6056
posts, err := ParsePosts(postsFS)
6157
if err != nil {
@@ -635,17 +631,47 @@ func Run(site Site) error {
635631
w.Header().Set("Content-Type", "text/html")
636632
_ = page(site, pageInfo, notFound()).Render(r.Context(), w)
637633
})
638-
server := &http.Server{
634+
httpServer := &http.Server{
639635
ReadHeaderTimeout: 3 * time.Second,
640636
Handler: router,
641637
}
642638
l, err := net.Listen("tcp", ":3000")
643639
if err != nil {
644640
return fmt.Errorf("listening: %w", err)
645641
}
646-
if err := server.Serve(l); err != nil {
647-
return fmt.Errorf("starting server: %w", err)
648-
}
642+
defer l.Close()
643+
644+
slog.Info(
645+
"website started",
646+
"commit",
647+
site.Commit,
648+
"production",
649+
site.IsProduction,
650+
"address",
651+
l.Addr().String(),
652+
)
653+
654+
go func() {
655+
if err := httpServer.Serve(l); err != nil {
656+
if errors.Is(err, http.ErrServerClosed) {
657+
return
658+
}
659+
slog.Error("serving website", "error", err)
660+
}
661+
}()
662+
var wg sync.WaitGroup
663+
wg.Add(1)
664+
go func() {
665+
defer wg.Done()
666+
<-ctx.Done()
667+
slog.Info("shutting down http server")
668+
shutdownCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
669+
defer cancel()
670+
if err := httpServer.Shutdown(shutdownCtx); err != nil {
671+
slog.Error("shutting down http server", "error", err)
672+
}
673+
}()
674+
wg.Wait()
649675
return nil
650676
}
651677

0 commit comments

Comments
 (0)