Project ⏱ 25 min read

10 · Life Cycle

How the app starts, handles a request, and shuts down

Application Startup

Watch each init step run in order
main()
├── config.Load() // read env vars via Viper
├── logger.New() // initialize structured logger
├── app.initDatabase() // GORM → PostgreSQL (with retry)
├── app.initRODatabase() // read-only replica
├── app.initRedis() // Redis client (optional)
└── app.initFiber()
├── fiber.New(config) // Fiber app + error handler
├── app.Use(recover) // catch panics, return 500
├── app.Use(RequestID) // attach X-Request-ID
├── app.Use(ContextEnrichment…) // ClientIP · OriginContext
├── app.Use(BasicAuth) // validate ALLOWED_CLIENTS
├── app.Use(UserID · Logging) // extract user, log every req
└── routes.SetupRoutes() // repos → services → handlers

Middleware order matters. RequestID must run before Logging so the trace ID is available in logs. BasicAuth must run before route handlers.

HTTP Request Journey

Happy path: Handler → DB read → DB write → 200 OK
POST /coupon/api/v1/user-coupon/
[recover middleware] — catches any panic, returns 500
[RequestID middleware] — attaches trace ID to context
[BasicAuth middleware] — validates Authorization header
[Logging middleware] — logs "request received" with trace ID
userCouponHandler.IssueCoupon(c)
c.BodyParser(&req) · validate(req) · c.UserContext()
userCouponService.IssueCoupon(ctx, params)
validate rules · couponRepo.GetByID → PostgreSQL read ✓ · userCouponRepo.Create → PostgreSQL write ✓
[ErrorHandlerMiddleware] — formats errors as JSON
Response: 200 OK {"data": {...}}

Graceful Shutdown

Simulate receiving SIGTERM
⚡ SIGTERM received
├── fiber.ShutdownWithContext(30s) // stop new requests, drain in-flight
├── db.Close() // close PostgreSQL (main)
├── roDB.Close() // close read-only replica
├── redis.Close() // close Redis client
└── logger.Close() // flush log buffer
✓ Process exited cleanly

Kubernetes sends SIGTERM before killing a pod. The 30-second timeout gives in-flight requests time to complete. This is why make run stops cleanly on Ctrl-C.

Key Takeaways