mirror of
https://github.com/hanzo-fi/stack.git
synced 2026-10-30 20:34:43 +00:00
107 lines
2.3 KiB
Go
107 lines
2.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"os"
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
"github.com/formancehq/stack/libs/go-libs/errorsutils"
|
|
"github.com/formancehq/stack/libs/go-libs/logging"
|
|
"github.com/spf13/cobra"
|
|
"go.uber.org/fx"
|
|
)
|
|
|
|
const DebugFlag = "debug"
|
|
|
|
func BindFlags(cmd *cobra.Command) {
|
|
cmd.PersistentFlags().Bool(DebugFlag, false, "Debug mode")
|
|
cmd.PersistentFlags().Bool(logging.JsonFormattingLoggerFlag, false, "Format logs as json")
|
|
}
|
|
|
|
type App struct {
|
|
options []fx.Option
|
|
output io.Writer
|
|
}
|
|
|
|
func (a *App) Run(ctx context.Context) error {
|
|
logger := GetDefaultLogger(a.output, viper.GetBool(DebugFlag))
|
|
logger.Infof("Starting application")
|
|
logger.Debugf("Environment variables")
|
|
for _, v := range os.Environ() {
|
|
logger.Debugf(v)
|
|
}
|
|
|
|
app := a.newFxApp(logger)
|
|
if err := app.Start(logging.ContextWithLogger(ctx, logger)); err != nil {
|
|
switch {
|
|
case errorsutils.IsErrorWithExitCode(err):
|
|
logger.Errorf("Error: %v", err)
|
|
// We want to have a specific exit code for the error
|
|
os.Exit(err.(*errorsutils.ErrorWithExitCode).ExitCode)
|
|
default:
|
|
return err
|
|
}
|
|
}
|
|
|
|
var exitCode int
|
|
select {
|
|
case <-ctx.Done():
|
|
case shutdownSignal := <-app.Wait():
|
|
// <-app.Done() is a signals channel, it means we have to call the
|
|
// app.Stop in order to gracefully shutdown the app
|
|
exitCode = shutdownSignal.ExitCode
|
|
}
|
|
|
|
logger.Infof("Stopping app...")
|
|
|
|
if err := app.Stop(logging.ContextWithLogger(contextWithLifecycle(
|
|
context.Background(), // Don't reuse original context as it can have been cancelled, and we really need to properly stop the app
|
|
lifecycleFromContext(ctx),
|
|
), logger)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if exitCode != 0 {
|
|
os.Exit(exitCode)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *App) newFxApp(logger logging.Logger) *fx.App {
|
|
options := append(a.options,
|
|
fx.NopLogger,
|
|
fx.Supply(fx.Annotate(logger, fx.As(new(logging.Logger)))),
|
|
fx.Invoke(func(lc fx.Lifecycle) {
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
markAsAppReady(ctx)
|
|
|
|
return nil
|
|
},
|
|
})
|
|
}),
|
|
)
|
|
options = append([]fx.Option{
|
|
fx.Invoke(func(lc fx.Lifecycle) {
|
|
lc.Append(fx.Hook{
|
|
OnStop: func(ctx context.Context) error {
|
|
markAsAppStopped(ctx)
|
|
|
|
return nil
|
|
},
|
|
})
|
|
}),
|
|
}, options...)
|
|
return fx.New(options...)
|
|
}
|
|
|
|
func New(output io.Writer, options ...fx.Option) *App {
|
|
return &App{
|
|
options: options,
|
|
output: output,
|
|
}
|
|
}
|