1/*
2GoCleanup: kinda like atexit()...
3
4GoCleanup packages allows you to register cleanup functions.
5These are called whenever the current process receives a SIGINT or SIGTERM
6
7You can also invoke the cleanup functions by calling Cleanup().
8
9Unfortunately, it is not possible for cleanup to intercept calls to os.Exit() and perform cleanup befor the
10process exits.  Instead of os.Exit, you can use cleanup.Exit()
11
12Cleanup is especially useful when forking off external processes.  You can register
13callbacks with this package to tear down these external processes.
14*/
15
16package gocleanup
17
18import (
19	"os"
20	"os/signal"
21	"syscall"
22)
23
24var cleanupFuncs []func()
25var capturingSignals bool
26
27//Register a cleanup function.  This will be called when:
28//- a call is made to Cleanup()
29//- a call is made to Exit()
30//- the current process receives SIGINT or SIGTERM
31func Register(f func()) {
32	cleanupFuncs = append(cleanupFuncs, f)
33	if !capturingSignals {
34		capturingSignals = true
35		go func() {
36			c := make(chan os.Signal, 1)
37			signal.Notify(c, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
38
39			<-c
40			Exit(1)
41		}()
42	}
43}
44
45//Cleanup invokes all registered cleanup functions
46//all registered cleanup functions are subsequently removed
47func Cleanup() {
48	for _, f := range cleanupFuncs {
49		f()
50	}
51	cleanupFuncs = []func(){}
52}
53
54//Exit invokes all registered cleanup functions, then exits
55func Exit(status int) {
56	Cleanup()
57	os.Exit(status)
58}
59