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
- Startup order: config → logger → DB → Redis → Fiber → middleware → routes
- Middleware runs in registration order — RequestID before Logging, BasicAuth before handlers
- Every request carries a trace ID through context — all logs are correlated
- Graceful shutdown: stop accepting requests → drain in-flight → close connections