The signal handler cancels the shared context, but the Gin HTTP server is started with router.Run(...) and never receives a shutdown signal. As a result, the process can block forever in WaitGroup.Wait() after SIGINT or SIGTERM.
Evidence
cmd/bridge/main.go:42-45 handles SIGINT/SIGTERM by calling cancel()
cmd/bridge/main.go:57-60 runs the IMAP watcher, which respects the context and returns
cmd/bridge/main.go:66-73 starts the HTTP server with router.Run(cfg.ListenAddr)
There is no owned http.Server instance and no call to Shutdown() on cancellation
Why this is a problem
On shutdown, the IMAP goroutine can stop, but the HTTP goroutine stays blocked inside router.Run(...).
The main goroutine waits on the WaitGroup, so the process may never exit cleanly.
In Docker or process supervisors, this can turn graceful stop into a forced kill.
Expected behavior
Own the HTTP server explicitly.
On context cancellation or signal, call Shutdown() with a timeout.
Let both goroutines finish so WaitGroup.Wait() can return.
Impact
Graceful shutdown is currently incomplete and can leave the service hanging during deploys or container stops.
## Summary
The signal handler cancels the shared context, but the Gin HTTP server is started with `router.Run(...)` and never receives a shutdown signal. As a result, the process can block forever in `WaitGroup.Wait()` after `SIGINT` or `SIGTERM`.
## Evidence
- `cmd/bridge/main.go:42-45` handles `SIGINT/SIGTERM` by calling `cancel()`
- `cmd/bridge/main.go:57-60` runs the IMAP watcher, which respects the context and returns
- `cmd/bridge/main.go:66-73` starts the HTTP server with `router.Run(cfg.ListenAddr)`
- There is no owned `http.Server` instance and no call to `Shutdown()` on cancellation
## Why this is a problem
- On shutdown, the IMAP goroutine can stop, but the HTTP goroutine stays blocked inside `router.Run(...)`.
- The main goroutine waits on the `WaitGroup`, so the process may never exit cleanly.
- In Docker or process supervisors, this can turn graceful stop into a forced kill.
## Expected behavior
- Own the HTTP server explicitly.
- On context cancellation or signal, call `Shutdown()` with a timeout.
- Let both goroutines finish so `WaitGroup.Wait()` can return.
## Impact
Graceful shutdown is currently incomplete and can leave the service hanging during deploys or container stops.
cmd/bridge/main.go:69 — router.Run() blocks indefinitely, no http.Server owned, no Shutdown() on context cancel. Process hangs at wg.Wait().
Implementation Plan
Single-file change in cmd/bridge/main.go:
Replace router.Run(cfg.ListenAddr) with explicit http.Server
Start server in goroutine via srv.ListenAndServe()
Watch ctx.Done() and call srv.Shutdown() with 5s timeout
Keep existing error logging and cancel() on server error
No changes to api/router.go or any other package.
## Validation: Issue confirmed
`cmd/bridge/main.go:69` — `router.Run()` blocks indefinitely, no `http.Server` owned, no `Shutdown()` on context cancel. Process hangs at `wg.Wait()`.
## Implementation Plan
Single-file change in `cmd/bridge/main.go`:
1. Replace `router.Run(cfg.ListenAddr)` with explicit `http.Server`
2. Start server in goroutine via `srv.ListenAndServe()`
3. Watch `ctx.Done()` and call `srv.Shutdown()` with 5s timeout
4. Keep existing error logging and `cancel()` on server error
No changes to `api/router.go` or any other package.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
The signal handler cancels the shared context, but the Gin HTTP server is started with
router.Run(...)and never receives a shutdown signal. As a result, the process can block forever inWaitGroup.Wait()afterSIGINTorSIGTERM.Evidence
cmd/bridge/main.go:42-45handlesSIGINT/SIGTERMby callingcancel()cmd/bridge/main.go:57-60runs the IMAP watcher, which respects the context and returnscmd/bridge/main.go:66-73starts the HTTP server withrouter.Run(cfg.ListenAddr)http.Serverinstance and no call toShutdown()on cancellationWhy this is a problem
router.Run(...).WaitGroup, so the process may never exit cleanly.Expected behavior
Shutdown()with a timeout.WaitGroup.Wait()can return.Impact
Graceful shutdown is currently incomplete and can leave the service hanging during deploys or container stops.
Validation: Issue confirmed
cmd/bridge/main.go:69—router.Run()blocks indefinitely, nohttp.Serverowned, noShutdown()on context cancel. Process hangs atwg.Wait().Implementation Plan
Single-file change in
cmd/bridge/main.go:router.Run(cfg.ListenAddr)with explicithttp.Serversrv.ListenAndServe()ctx.Done()and callsrv.Shutdown()with 5s timeoutcancel()on server errorNo changes to
api/router.goor any other package.