|
| 1 | +# Bun Graceful Shutdown Example |
| 2 | + |
| 3 | +This example demonstrates the graceful shutdown feature of the Bun adapter for `react-router-hono-server`. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- ✅ Graceful shutdown hook (`onGracefulShutdown`) |
| 8 | +- ✅ Signal handler setup (SIGTERM, SIGINT) |
| 9 | +- ✅ Clean resource cleanup before process exit |
| 10 | +- ✅ Production-ready pattern |
| 11 | + |
| 12 | +## How It Works |
| 13 | + |
| 14 | +### 1. Server Configuration |
| 15 | + |
| 16 | +In [app/server.ts](./app/server.ts), simply configure the server with a graceful shutdown callback: |
| 17 | + |
| 18 | +```ts |
| 19 | +export default createHonoServer({ |
| 20 | + onGracefulShutdown: async () => { |
| 21 | + console.log('🧹 Running cleanup tasks...'); |
| 22 | + // Your cleanup logic here (close DB connections, etc.) |
| 23 | + await new Promise(resolve => setTimeout(resolve, 1000)); |
| 24 | + console.log('✅ Cleanup complete!'); |
| 25 | + }, |
| 26 | +}); |
| 27 | +``` |
| 28 | + |
| 29 | +**That's it!** The Bun adapter automatically registers SIGTERM and SIGINT signal handlers when you provide an `onGracefulShutdown` callback. No additional setup needed. |
| 30 | + |
| 31 | +### 2. Shutdown Flow |
| 32 | + |
| 33 | +When you send a SIGTERM or SIGINT signal (e.g., Ctrl+C): |
| 34 | + |
| 35 | +1. Automatic signal handler is triggered |
| 36 | +2. Server stops accepting new connections |
| 37 | +3. Existing inflight requests complete |
| 38 | +4. `onGracefulShutdown` callback executes |
| 39 | +5. Process exits cleanly |
| 40 | + |
| 41 | +## Running the Example |
| 42 | + |
| 43 | +### Development |
| 44 | + |
| 45 | +```bash |
| 46 | +bun install |
| 47 | +bun run dev |
| 48 | +``` |
| 49 | + |
| 50 | +### Production |
| 51 | + |
| 52 | +```bash |
| 53 | +bun run build |
| 54 | +bun run start |
| 55 | +``` |
| 56 | + |
| 57 | +Then press `Ctrl+C` to test the graceful shutdown. You should see: |
| 58 | + |
| 59 | +``` |
| 60 | +📡 Received SIGINT, shutting down gracefully... |
| 61 | +Initiating graceful shutdown... |
| 62 | +Server stopped, all requests completed |
| 63 | +🧹 Running cleanup tasks... |
| 64 | +✅ Cleanup complete! |
| 65 | +Cleanup callback completed |
| 66 | +👋 Shutdown complete |
| 67 | +``` |
| 68 | + |
| 69 | +## Key Files |
| 70 | + |
| 71 | +- [app/server.ts](./app/server.ts) - Server configuration with graceful shutdown callback |
| 72 | +- [app/routes/_index.tsx](./app/routes/_index.tsx) - Demo page explaining the feature |
| 73 | + |
| 74 | +## Notes |
| 75 | + |
| 76 | +- The `onGracefulShutdown` callback only runs in **production mode** |
| 77 | +- During development, the callback is ignored |
| 78 | +- Signal handlers (SIGTERM, SIGINT) are automatically registered in production |
| 79 | +- The server waits indefinitely for inflight connections to complete |
| 80 | + |
| 81 | +## Deployment |
| 82 | + |
| 83 | +When deploying to production environments (Docker, Kubernetes, etc.), ensure: |
| 84 | + |
| 85 | +1. Your container/orchestrator sends SIGTERM for graceful shutdown |
| 86 | +2. Allow sufficient time for graceful shutdown before force kill |
| 87 | +3. Configure health checks to stop sending traffic during shutdown |
| 88 | + |
| 89 | +### Docker Example |
| 90 | + |
| 91 | +```dockerfile |
| 92 | +FROM oven/bun:latest |
| 93 | +WORKDIR /app |
| 94 | +COPY . . |
| 95 | +RUN bun install |
| 96 | +RUN bun run build |
| 97 | +CMD ["bun", "./scripts/start.ts"] |
| 98 | + |
| 99 | +# Important: Use exec form to handle signals properly |
| 100 | +# OR use: ENTRYPOINT ["bun", "./scripts/start.ts"] |
| 101 | +``` |
| 102 | + |
| 103 | +### Kubernetes Example |
| 104 | + |
| 105 | +```yaml |
| 106 | +spec: |
| 107 | + containers: |
| 108 | + - name: app |
| 109 | + lifecycle: |
| 110 | + preStop: |
| 111 | + exec: |
| 112 | + command: ["/bin/sh", "-c", "sleep 5"] |
| 113 | + terminationGracePeriodSeconds: 30 |
| 114 | +``` |
| 115 | +
|
| 116 | +This gives the app time to finish graceful shutdown before Kubernetes force-kills the pod. |
0 commit comments