Skip to content

Commit c246c61

Browse files
committed
60sec graceful shutdown
1 parent c722f0d commit c246c61

6 files changed

Lines changed: 794 additions & 40 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ For installation instructions, configuration options, and detailed setup guides,
8787

8888
## 🤝 Contributing
8989

90-
We welcome contributions! Please see our [Contributing Guide](https://docs.notifuse.com/development/contributing) for details.
90+
We welcome contributions!
9191

9292
1. Fork the repository
9393
2. Create a feature branch

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# TODO
22

33
- docs: email providers
4-
- docker hub publish image
4+
- docs: newsletter input form example
55

66
## Eventual features
77

cmd/api/main.go

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func runServer(cfg *config.Config, appLogger logger.Logger) error {
3636
return err
3737
}
3838

39-
// Set up graceful shutdown
39+
// Set up graceful shutdown - single channel for all signals
4040
shutdown := make(chan os.Signal, 1)
4141
signalNotify(shutdown, os.Interrupt, syscall.SIGTERM)
4242

@@ -55,20 +55,60 @@ func runServer(cfg *config.Config, appLogger logger.Logger) error {
5555
}
5656
return err
5757
case sig := <-shutdown:
58-
appLogger.WithField("signal", sig.String()).Info("Shutdown signal received")
58+
appLogger.WithField("signal", sig.String()).Info("Shutdown signal received - starting graceful shutdown")
59+
appLogger.Info("Send signal again (Ctrl+C) to force immediate shutdown")
60+
61+
// Configure app shutdown timeout for long-running tasks (55+ seconds)
62+
// Set to 65 seconds to allow tasks to complete or save progress
63+
appInstance.SetShutdownTimeout(65 * time.Second)
5964

6065
// Create a context with timeout for graceful shutdown
61-
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
66+
// Use 70 seconds to give 5 seconds buffer beyond app's internal timeout
67+
ctx, cancel := context.WithTimeout(context.Background(), 70*time.Second)
6268
defer cancel()
6369

64-
// Attempt graceful shutdown
65-
if err := appInstance.Shutdown(ctx); err != nil {
66-
appLogger.WithField("error", err.Error()).Error("Error during shutdown")
67-
return err
70+
// Log current active requests
71+
activeRequests := appInstance.GetActiveRequestCount()
72+
appLogger.WithField("active_requests", activeRequests).Info("Starting graceful shutdown")
73+
74+
// Create a new channel for force shutdown (after first signal received)
75+
forceShutdown := make(chan os.Signal, 1)
76+
signalNotify(forceShutdown, os.Interrupt, syscall.SIGTERM)
77+
78+
// Start graceful shutdown in a goroutine
79+
shutdownDone := make(chan error, 1)
80+
go func() {
81+
shutdownDone <- appInstance.Shutdown(ctx)
82+
}()
83+
84+
// Wait for either graceful shutdown completion or forced shutdown signal
85+
select {
86+
case err := <-shutdownDone:
87+
if err != nil {
88+
appLogger.WithField("error", err.Error()).Error("Error during graceful shutdown")
89+
return err
90+
}
91+
appLogger.Info("Server shut down gracefully")
92+
return nil
93+
case forceSig := <-forceShutdown:
94+
appLogger.WithField("signal", forceSig.String()).Warn("Force shutdown signal received - terminating immediately")
95+
appLogger.Warn("Some requests may be interrupted!")
96+
97+
// Cancel the graceful shutdown context to force immediate shutdown
98+
cancel()
99+
100+
// Wait a brief moment for the shutdown to acknowledge the cancellation
101+
select {
102+
case err := <-shutdownDone:
103+
if err != nil {
104+
appLogger.WithField("error", err.Error()).Error("Error during forced shutdown")
105+
}
106+
case <-time.After(2 * time.Second):
107+
appLogger.Warn("Forced shutdown timeout - exiting immediately")
108+
}
109+
110+
return fmt.Errorf("forced shutdown")
68111
}
69-
70-
appLogger.Info("Server shut down gracefully")
71-
return nil
72112
}
73113
}
74114

0 commit comments

Comments
 (0)