Ensuring resource cleanup when app is killed

1,053 views
Skip to first unread message

Sundar Nadathur

unread,
Jan 24, 2018, 8:24:37 AM1/24/18
to golang-nuts
My golang application creates UNIX sockets in specific paths: /mypath/name1.sock, /mypath/name2.sock etc. It then launches a go routine that listens to one or more of those sockets. I need to ensure that they get cleaned up (removed) at the end. I tried the obvious thing -- use defer in main() -- and eschewed the use of os.Exit() and log.Fatal(), since they don't ensure that defer statements are called.

However, signals like ^C also apparently cause forced termination and don't run the defer statements. So, I have experimented with a signal handler registered from main(). However, it seems that the ^C is going to the go routine that is actually listening on the socket: I don't see the signal handler running.

What is a good way to ensure that the resources are always cleaned up even in the presence of go routines and signals?

I have looked at related posts like these.

Tamás Gulácsi

unread,
Jan 24, 2018, 9:08:25 AM1/24/18
to golang-nuts
func main() {
if err := Main(); err != nil {
log.Fatal(err)
}
}

func Main() error {
ctx, cancel := cintext.WithCanvel(context.Background())
defer cancel()
sigCh := make(chan signal.Signal, 1)
go func() {
<-sigCh
cancel()
}
signal.Notify(sigCh, signal.Interrupt)

...

return nil
}

Ian Lance Taylor

unread,
Jan 24, 2018, 9:31:53 AM1/24/18
to Sundar Nadathur, golang-nuts
To handle a signal in a Go program, use the os/signal package. I'm
not sure what you mean when you say that you registered a signal
handler.

That said, the only fully reliable way to do this is to use a separate
wrapper program. The wrapper program will run the real program, and
then remove the sockets when the real program exits. That is true in
any language. There are too many different ways for a program to die,
and there is no way for a program in any language to reliably run code
as it is dying.

Ian

Sundar Nadathur

unread,
Jan 24, 2018, 2:07:49 PM1/24/18
to golang-nuts
Thank you both for the replies. 

Hi Tamas, I am wondering about:
  go func() {
    <-sigCh
    cancel()
  }

If the program exits normally, presumably sigCh channel will not get notified, and this goroutine will continue to run. How do we ensure that it quits on normal program exit? 

Regards,
Sundar 

Tamás Gulácsi

unread,
Jan 24, 2018, 3:05:35 PM1/24/18
to golang-nuts
if the main goroutine exits, all other goroutines exit, too.

Sundar Nadathur

unread,
Jan 24, 2018, 5:03:15 PM1/24/18
to golang-nuts
I am probably mis-understanding or missing something. The golang spec says:
    Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.

I gather that the context mechanism addresses this issue, by requiring every relevant go routine to get a context as a parameter and to check for ctx.Done channel. Since calling cancel() would send a message through that channel, every goroutine that is designed to listen on that channel would 'get the message' and can do their own cleanup/exit.

However, this specific goroutine does not receive the context. The golang spec seems to say that it is not guaranteed to exit when the app dies or exits. Please clarify.

Regards,
Sundar

Matt Harden

unread,
Jan 24, 2018, 6:23:04 PM1/24/18
to Sundar Nadathur, golang-nuts
When the program exits, all goroutines die instantly. The doc is saying that the program does not wait for any goroutine to complete except the "main" goroutine (the one that invoked the function main at startup). If you do want to wait for other goroutines to exit before exiting the program, which is often something you do want, that can be done using sync.WaitGroup or other synchronization tools like channels. In the case of Tamas's goroutine, nothing in main waits for it, assuming the program isn't sent an interrupt signal, so the goroutine never "completes". It does "exit" though, because all goroutines are part of the program, and when the program exits, it exits entirely. Any goroutine that was running as part of the program isn't running anymore, and in fact doesn't even "exist" in any meaningful sense anymore.

You are correct that contexts can be used to inform goroutines when to perform cleanup steps and/or exit cleanly, but if you want to ensure that the cleanup actually completes, you need to wait for the goroutine to finish before returning from main (or running os.Exit, log.Fatal, panicking without recovering, etc.). Otherwise the goroutine may abruptly stop running at any time as the program exits.

I hope that helps to clarify the documentation for you.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sundar Nadathur

unread,
Jan 24, 2018, 7:48:34 PM1/24/18
to golang-nuts
Thank you! Got it.

Regards,
Sundar
Reply all
Reply to author
Forward
0 new messages