diff --git a/cmd/cgat/main.go b/cmd/cgat/main.go
index e8447eb6ce18d6fb5b86e46c499a70c8b96f5e90..88a4c2692317a9610a279fe9d998159230f8e2cd 100644
--- a/cmd/cgat/main.go
+++ b/cmd/cgat/main.go
@@ -2,11 +2,14 @@ package main
 
 import (
 	"context"
+	"net/http"
+	_ "net/http/pprof"
+	"time"
+
 	"gfx.cafe/gfx/pggat/lib/config"
 	"gfx.cafe/gfx/pggat/lib/gat/gatling"
+	"gfx.cafe/util/go/graceful"
 	"git.tuxpa.in/a/zlog/log"
-	"net/http"
-	_ "net/http/pprof"
 )
 
 // test config, should be changed
@@ -25,8 +28,9 @@ func main() {
 	}
 	g := gatling.NewGatling(conf)
 	log.Println("listening on port", conf.General.Port)
-	err = g.ListenAndServe(context.Background())
-	if err != nil {
-		panic(err)
-	}
+	graceful.Handler(g.ListenAndServe, func(ctx context.Context) error {
+		log.Println("shutting down in 3 seconds...")
+		time.Sleep(3 * time.Second)
+		return nil
+	})
 }
diff --git a/go.mod b/go.mod
index feff4852ac17ab873e632cbde4440e7dc7b25402..fd75d65b028cfc2389d48d956dc928ff29eb334a 100644
--- a/go.mod
+++ b/go.mod
@@ -17,6 +17,7 @@ require (
 )
 
 require (
+	gfx.cafe/util/go/graceful v0.0.0-20220913082111-9770431e98e9 // indirect
 	github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 // indirect
 	github.com/cockroachdb/apd v1.1.1-0.20181017181144-bced77f817b4 // indirect
 	github.com/cockroachdb/errors v1.8.2 // indirect
diff --git a/go.sum b/go.sum
index a23ece5ff68027e7542bcb55a829eacdf0b89c4e..1efff19f0129c2cf2a74831221cbbfd9d239875e 100644
--- a/go.sum
+++ b/go.sum
@@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 gfx.cafe/util/go/bufpool v0.0.0-20220906091724-3a24b7f40ccf h1:ya4IK1D+Kq0DrFdrrZ7tjmp3BgoO4v5sCAeUytR6j1U=
 gfx.cafe/util/go/bufpool v0.0.0-20220906091724-3a24b7f40ccf/go.mod h1:+DiyiCOBGS9O9Ce4ewHQO3Y59h66WSWAbgZZ2O2AYYw=
+gfx.cafe/util/go/graceful v0.0.0-20220913082111-9770431e98e9 h1:Z0RRPRbz5Bt7yu6v+RzLCAKm0YNcrwNGLMs9UVs8NsU=
+gfx.cafe/util/go/graceful v0.0.0-20220913082111-9770431e98e9/go.mod h1:sO44FAgBZXic9FwJaJHX1mI9vt1e3CRe0X/3bwnMRho=
 gfx.cafe/util/go/lambda v0.0.0-20220906200602-98a6b35a1b42 h1:8mKA+jVj7l3sM/s6CjqF/5DhAIWftIhit0XqkswzkAg=
 gfx.cafe/util/go/lambda v0.0.0-20220906200602-98a6b35a1b42/go.mod h1:+qAj+4kl6uABj/3RqR84AwHnm+vYyYoPwLJdTR3GgRc=
 git.tuxpa.in/a/lambda v0.0.0-20220903040836-72d2bd6dc070 h1:CuEIvPmhTWKmMMoJnsP2xOoWRFOFB7cZABONrSQaiDc=
diff --git a/lib/gat/gatling/gatling.go b/lib/gat/gatling/gatling.go
index 2c79b3ca7ee8755922e049d8711a9b069fa2b93c..7c9085f817ab953a66e977012a414a66eef0c619 100644
--- a/lib/gat/gatling/gatling.go
+++ b/lib/gat/gatling/gatling.go
@@ -119,22 +119,25 @@ func (g *Gatling) ListenAndServe(ctx context.Context) error {
 	if err != nil {
 		return err
 	}
-	for {
-		var c net.Conn
-		c, err = ln.Accept()
-		if err != nil {
-			return err
-		}
-		go func() {
-			err = g.handleConnection(ctx, c)
+	go func() {
+		for {
+			var c net.Conn
+			c, err = ln.Accept()
 			if err != nil {
-				if err != io.EOF {
-					log.Println("disconnected:", err)
-				}
-				return
+				log.Println("failed to accept connection:", err)
 			}
-		}()
-	}
+			go func() {
+				err = g.handleConnection(ctx, c)
+				if err != nil {
+					if err != io.EOF {
+						log.Println("disconnected:", err)
+					}
+					return
+				}
+			}()
+		}
+	}()
+	return nil
 }
 
 // TODO: TLS