Graceful shutdown is a non-forceful alternative to task cancellation. It allows services to clean up resources or finish ongoing work before exiting.
To enable graceful shutdown at the application level, configure ServiceGroup with gracefulShutdownSignals (e.g., [.sigterm]).
To make your service logic responsive to a graceful shutdown, use the cancelOnGracefulShutdown() method on any AsyncSequence. This ensures that loops iterating over streams or requests terminate when the shutdown signal is received.
Note: ServiceGroup shuts down services in reverse startup order, waiting for each service's run() method to return before proceeding to the next.
import ServiceLifecycle
import Logging
struct StreamingService: Service {
// ... implementation ...
func run() async throws {
await withDiscardingTaskGroup { group in
// Use cancelOnGracefulShutdown() to stop iteration during shutdown
for stream in makeStreams().cancelOnGracefulShutdown() {
group.addTask {
await streamHandler(stream.requestStream, stream.responseWriter)
}
}
}
}
}
@main
struct Application {
static let logger = Logger(label: "Application")
static func main() async throws {
let streamingService = StreamingService(streamHandler: { requestStream, responseWriter in
// Use cancelOnGracefulShutdown() inside handlers as well
for await request in requestStream.cancelOnGracefulShutdown() {
responseWriter.write("response")
}
})
let serviceGroup = ServiceGroup(
services: [streamingService],
gracefulShutdownSignals: [.sigterm],
logger: logger
)
try await serviceGroup.run()
}
}