To implement graceful shutdown and cleanup for I/O operations in Go, you can follow these steps:
Create a context.Context
and pass it to the functions or methods that perform the I/O operations. This context will be used to signal cancellation.
Use the context.Context
in your I/O operations and regularly check for cancellation using ctx.Done()
.
Implement a signal handler to catch termination signals (e.g., SIGINT
or SIGTERM
) and call ctx.Cancel()
to signal cancellation.
Use channels or other synchronization mechanisms to notify the functions performing I/O operations about the cancellation signal.
Handle the cancellation signal in the I/O operations and gracefully shut down the operations. This can include closing files, releasing resources, or terminating network connections.
Here's an example of how you can implement graceful shutdown and cleanup for file I/O operations:
package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
)
func main() {
// Create a context and cancel function
ctx, cancel := context.WithCancel(context.Background())
// Handle termination signals
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
cancel() // Signal cancellation
}()
// Perform I/O operations
go func() {
err := readFile(ctx, "file.txt")
if err != nil {
log.Println("Error reading file:", err)
}
}()
// Wait for the context to be done
<-ctx.Done()
// Perform cleanup operations
log.Println("Cleaning up...")
// ...
log.Println("Shutdown complete")
}
func readFile(ctx context.Context, filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// Read from file
for {
select {
case <-ctx.Done():
// Context canceled
return ctx.Err()
default:
// Continue reading
// ...
}
}
return nil
}
In this example, cancel()
is called when a termination signal is received. The readFile()
function checks for cancellation and returns if the context is canceled. Cleanup operations can be performed after the context is done.