fix: child process not exit when recive term signal (#418)

* fix: child process not exit when recive term signal

Signed-off-by: yxxhero <aiopsclub@163.com>

* fix: wait for clean done

Signed-off-by: Yusuke Kuoka <ykuoka@gmail.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
Co-authored-by: Yusuke Kuoka <ykuoka@gmail.com>
This commit is contained in:
yxxhero 2022-10-09 16:51:52 +08:00 committed by GitHub
parent ad257554c9
commit 6a36f34c7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 21 deletions

24
main.go
View File

@ -1,19 +1,43 @@
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/helmfile/helmfile/cmd"
"github.com/helmfile/helmfile/pkg/app"
"github.com/helmfile/helmfile/pkg/config"
"github.com/helmfile/helmfile/pkg/errors"
)
func main() {
var sig os.Signal
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig = <-sigs
}()
globalConfig := new(config.GlobalOptions)
rootCmd, err := cmd.NewRootCmd(globalConfig, os.Args[1:])
errors.HandleExitCoder(err)
if err := rootCmd.Execute(); err != nil {
if sig != nil {
fmt.Fprintln(os.Stderr, err)
app.CleanWaitGroup.Wait()
// See http://tldp.org/LDP/abs/html/exitcodes.html
switch sig {
case syscall.SIGINT:
os.Exit(130)
case syscall.SIGTERM:
os.Exit(143)
}
}
errors.HandleExitCoder(err)
}
}

View File

@ -5,12 +5,10 @@ import (
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"sort"
"strings"
"sync"
"syscall"
"text/tabwriter"
"github.com/variantdev/vals"
@ -24,6 +22,8 @@ import (
"github.com/helmfile/helmfile/pkg/state"
)
var CleanWaitGroup sync.WaitGroup
// App is the main application object.
type App struct {
OverrideKubeContext string
@ -776,7 +776,7 @@ func (a *App) getHelm(st *state.HelmState) helmexec.Interface {
func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*state.HelmState) (bool, []error)) error {
noMatchInHelmfiles := true
err := a.visitStateFiles(fileOrDir, defOpts, func(f, d string) error {
err := a.visitStateFiles(fileOrDir, defOpts, func(f, d string) (retErr error) {
opts := defOpts.DeepCopy()
if opts.CalleePath == "" {
@ -785,22 +785,6 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
st, err := a.loadDesiredStateFromYaml(f, opts)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
errs := []error{fmt.Errorf("received [%s] to shutdown ", sig)}
_ = context{app: a, st: st, retainValues: defOpts.RetainValuesFiles}.clean(errs)
// See http://tldp.org/LDP/abs/html/exitcodes.html
switch sig {
case syscall.SIGINT:
os.Exit(130)
case syscall.SIGTERM:
os.Exit(143)
}
}()
ctx := context{app: a, st: st, retainValues: defOpts.RetainValuesFiles}
if err != nil {
@ -864,7 +848,32 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
return appError(fmt.Sprintf("failed executing release templates in \"%s\"", f), tmplErr)
}
processed, errs := converge(templated)
var (
processed bool
errs []error
)
// Ensure every temporary files and directories generated while running
// the converge function is clean up before exiting this function in all the three cases below:
// - This function returned nil
// - This function returned an err
// - Helmfile received SIGINT or SIGTERM while running this function
// For the last case you also need a signal handler in main.go.
// Ideally though, this CleanWaitGroup should gone and be replaced by a context cancellation propagation.
// See https://github.com/helmfile/helmfile/pull/418 for more details.
CleanWaitGroup.Add(1)
defer func() {
defer CleanWaitGroup.Done()
cleanErr := context{app: a, st: templated, retainValues: defOpts.RetainValuesFiles}.clean(errs)
if retErr == nil {
retErr = cleanErr
} else if cleanErr != nil {
a.Logger.Debugf("Failed to clean up temporary files generated while processing %q: %v", templated.FilePath, cleanErr)
}
}()
processed, errs = converge(templated)
noMatchInHelmfiles = noMatchInHelmfiles && !processed
if opts.Reverse {
@ -874,7 +883,7 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
}
}
return context{app: a, st: templated, retainValues: defOpts.RetainValuesFiles}.clean(errs)
return nil
})
if err != nil {