How can I configure a long running Swift CLI with NIO respond to CTRL-C/SIGINT

I have long running socket client command line app utilizing SwiftNIO that is working fine, except that in terminal the CLI does not respond to the terminal's CTRL-C/SIGINT signal. Is this something configurable in NIO or is this simply a matter of writing my own signal handler?

We've set up a signal(SIGHUP) { ... } handler to deal with this.

ServiceLifecycle aims to solve this problem. The ServiceGroup can setup signal handlers and you can configure what signal leads to task cancellation or a graceful shutdown trigger. Graceful shutdown is a concept that ServiceLifecycle introduces and provides a way to gracefully teardown a process that isn't as forceful as task cancellation.

1 Like

Thanks all. My own signal handler that just exits doesn't alert the server its connection is dropping (because I'm not calling into NIO from the handler, is it correct I can only call C methods from the handler?). Will take a look at ServiceLifecycle, that seems like a clean approach.

is it correct I can only call C methods from the handler?

First up, terminology. A C signal handler is the callback function you pass to the C signal or sigaction routines.

As things currently stand, C signal handlers can only be written in C or C++. Moreover, there have severe limitations. Specifically, they can only call a short list of async signal safe functions. On Apple platforms that list is documented in the sigaction man page. Notably this doesn’t include malloc, printf, or exit |-:

Failure to follow those rules yields undefined behaviour, which can be Bad™ [1].

The standard way to write a signal handler in Swift is with a Dispatch signal source. The source event handler is scheduled on a Dispatch queue, which means it acts like any other multi-threaded code.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

[1] https://www.theregister.com/2024/07/01/regresshion_openssh/

1 Like