From 168a37ed98064f517e3f785374033600536ea6cf Mon Sep 17 00:00:00 2001 From: Rodrigo Fonseca Date: Thu, 19 Mar 2026 11:52:02 -0300 Subject: [PATCH] fix: return exit 1 on error The app was always finishing with success (exit code 0), even when the main loop finishes with an error. This change checks for error in the main loop and also the shutdown procedures and returns error (exit code 1) when an error is detected. --- app.go | 17 +++++++++++++---- go.mod | 10 +++++----- go.sum | 16 ++++++++-------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app.go b/app.go index a9a01d5..ebbec68 100644 --- a/app.go +++ b/app.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" "net/http/pprof" // Sadly, this also changes the DefaultMux to have the pprof URLs + "os" "os/signal" "sync" "sync/atomic" @@ -183,16 +184,22 @@ func (app *App) RunAndWait(mainLoop MainLoopFunc) { // Run main loop on a go-routine errs := make(chan error, 1) go app.runMainLoop(mainLoop, errs) - app.waitMainLoopOrSignal(errs) + err := app.waitMainLoopOrSignal(errs) // App is shutting down... app.readinessProbe.SetNotOk() app.waitGracePeriod() - _ = app.Shutdown(context.Background()) + shutdownErr := app.Shutdown(context.Background()) app.waitMainLoopFinish(10 * time.Second) // This forces kubernetes kills the pod if some other code is holding the main func. app.healthinessProbe.SetNotOk() + + // Ensure that the app finishes with an error code if the main loop finished by itself + // with an error or if the shutdown procedure failed with an error. + if err != nil || shutdownErr != nil { + os.Exit(1) + } } func (app *App) runMainLoop(mainLoop MainLoopFunc, errs chan<- error) { @@ -212,7 +219,7 @@ func (app *App) runMainLoop(mainLoop MainLoopFunc, errs chan<- error) { errs <- mainLoop(app.mainLoopCtx) } -func (app *App) waitMainLoopOrSignal(errs <-chan error) { +func (app *App) waitMainLoopOrSignal(errs <-chan error) error { gracefulShutdownCtx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer cancel() @@ -220,14 +227,16 @@ func (app *App) waitMainLoopOrSignal(errs <-chan error) { case err := <-errs: if err != nil { log.Error().Err(err).Msg("[app] Main Loop finished by itself with error.") + return err } else { - log.Warn().Msg("[app] Main Loop finished by itself without error. Ideally the main loop should be finished by a graceful shutdown handler.") + log.Info().Msg("[app] Main Loop finished by itself.") } case <-gracefulShutdownCtx.Done(): log.Info(). Dur("grace_period", app.shutdown.gracePeriod). Msg("[app] Graceful shutdown signal received.") } + return nil } func (app *App) waitGracePeriod() { diff --git a/go.mod b/go.mod index 6ca1f64..ff40c47 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,12 @@ module github.com/arquivei/go-app -go 1.25 +go 1.25.0 require ( github.com/prometheus/client_golang v1.23.2 github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 - golang.org/x/text v0.34.0 + golang.org/x/text v0.35.0 ) require ( @@ -20,9 +20,9 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect - github.com/prometheus/procfs v0.19.2 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/sys v0.41.0 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/sys v0.42.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d93f375..c62a146 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= -github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= -github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= @@ -46,15 +46,15 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=