bootstrap

package
v0.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 27, 2024 License: Apache-2.0 Imports: 17 Imported by: 0

README

Bootstrap

When writing a go-lanai application, the developer selects the go-lanai module they want to use. Bootstrap refers to the process of how the application instantiate the components needed by the modules and wires them together.

Under the hood, the bootstrapper keeps a registry of modules that's enabled in this application. A module is implemented as a group of fx.Provide and fx.Invoke options. When the app starts, all module added fx.provide and fx.invoke options are sorted and executed.

In go-lanai's module packages, you'll usually see a function like this:

package init

var Module = &bootstrap.Module{
	Name: "web",
	Precedence: web.MinWebPrecedence,
	PriorityOptions: []fx.Option{
		appconfig.FxEmbeddedDefaults(defaultConfigFS),
		fx.Provide(
			web.BindServerProperties,
			web.NewEngine,
			web.NewRegistrar),
		fx.Invoke(setup),
	},
}

// Use Allow service to include this module in main()
func Use() {
	bootstrap.Register(Module)
	bootstrap.Register(cors.Module)
}

This Use() method registers the module with the bootstrapper. The application code just needs to call the Use() function to indicate this module should be activated in the application.

Documentation

Index

Constants

View Source
const (
	FxCliRunnerGroup    = "bootstrap_cli_runner"
	CliRunnerModuleName = "CLI Runner"
)
View Source
const (
	LowestPrecedence  = int(^uint(0) >> 1)    // max int
	HighestPrecedence = -LowestPrecedence - 1 // min int

	FrameworkModulePrecedenceBandwidth = 799
	FrameworkModulePrecedence          = LowestPrecedence - 200*(FrameworkModulePrecedenceBandwidth+1)
	AnonymousModulePrecedence          = FrameworkModulePrecedence - 1
	PriorityModulePrecedence           = HighestPrecedence + 1
)
View Source
const (
	AppConfigPrecedence
	TracingPrecedence
	ActuatorPrecedence
	ConsulPrecedence
	VaultPrecedence
	AwsPrecedence
	TlsConfigPrecedence
	RedisPrecedence
	DatabasePrecedence
	KafkaPrecedence
	OpenSearchPrecedence
	WebPrecedence
	SecurityPrecedence
	DebugPrecedence
	ServiceDiscoveryPrecedence
	DistributedLockPrecedence
	TenantHierarchyAccessorPrecedence
	TenantHierarchyLoaderPrecedence
	TenantHierarchyModifierPrecedence
	HttpClientPrecedence
	SecurityIntegrationPrecedence
	SwaggerPrecedence
	StartupSummaryPrecedence
	// CommandLineRunnerPrecedence invocation should happen after everything else, in case it needs functionality from any other modules
	CommandLineRunnerPrecedence
)
View Source
const (
	CliFlagActiveProfile     = "active-profiles"
	CliFlagAdditionalProfile = "additional-profiles"
	CliFlagConfigSearchPath  = "config-search-path"
	CliFlagDebug             = "debug"
	EnvVarDebug              = "DEBUG"
)
View Source
const (
	PropertyKeyApplicationName = "application.name"
)

Variables

View Source
var (
	BuildVersion = "Unknown"
	BuildTime    = time.Now().Format(utils.ISO8601Seconds)
	BuildHash    = "Unknown"
	BuildDeps    = "github.com/cisco-open/go-lanai@develop"
)
View Source
var (
	BuildInfo = BuildInfoMetadata{
		Version:   BuildVersion,
		BuildTime: utils.ParseTime(utils.ISO8601Seconds, BuildTime),
		Hash:      BuildHash,
		Modules:   ModuleBuildInfoMap{},
	}

	BuildInfoMap map[string]interface{}
)

Functions

func AddBoolFlag

func AddBoolFlag(flagVar *bool, name string, defaultValue bool, usage string)

func AddInitialAppContextOptions

func AddInitialAppContextOptions(options ...ContextOption)

func AddOptions

func AddOptions(options ...fx.Option)

func AddStartContextOptions

func AddStartContextOptions(options ...ContextOption)

func AddStopContextOptions

func AddStopContextOptions(options ...ContextOption)

func AddStringFlag

func AddStringFlag(flagVar *string, name string, defaultValue string, usage string)

AddStringFlag should be called before Execute() to register flags that are supported

func DebugEnabled

func DebugEnabled() bool

DebugEnabled returns false by default, unless environment variable DEBUG is set or application start with --debug

func EnableCliRunnerMode

func EnableCliRunnerMode(runnerProviders ...interface{})

EnableCliRunnerMode should be called before Execute(), otherwise it won't run. "runnerProviders" are standard FX lifecycle functions that typically used with fx.Provide(...) signigure of "runnerProviders", but it should returns CliRunner or OrderedCliRunner, otherwise it won't run

example of runner provider:

func myRunner(di OtherDependencies) CliRunner {
	return func(ctx context.Context) error {
		// Do your stuff
		return err
	}
}

example of ordered runner provider:

func myRunner(di OtherDependencies) OrderedCliRunner {
	return bootstrap.OrderedCliRunner{
		Precedence: 0,
		CliRunner:  func(ctx context.Context) error {
			// Do your stuff
			return err
		},
	}
}

Using this pattern guarantees following things:

  1. The application is automatically shutdown after all lifecycle hooks finished
  2. The runner funcs are run after all other fx.Invoke
  3. All other "OnStop" are executed regardless if any hook function returns error (graceful shutdown)
  4. If any hook functions returns error, it reflected as non-zero process exit code
  5. Each cli runner are separately traced if tracing is enabled
  6. Any CliRunner without order is considered as having order 0

Note: calling this function repeatedly would override previous invocation (i.e. only the last invocation takes effect)

func Execute

func Execute()

Execute run globally configured application. "globally configured" means Module and fx.Options added via package level functions. e.g. Register or AddOptions It adds all child commands to the root command and sets flags appropriately. This is called by main.main(). It only needs to happen once to the rootCmd.

func ExecuteContainedApp

func ExecuteContainedApp(ctx context.Context, b *Bootstrapper)

ExecuteContainedApp is similar to Execute, but run with a separately configured Bootstrapper. In this mode, the bootstrapping process ignore any globally configured modules and options. This is usually called by test framework. Service developers normally don't use it directly

func NewAppCmd

func NewAppCmd(appName string, priorityOptions []fx.Option, regularOptions []fx.Option, cliOptions ...CliOptions)

func Register

func Register(m *Module)

Types

type App

type App struct {
	*fx.App
	// contains filtered or unexported fields
}

func (*App) EagerGetApplicationContext

func (app *App) EagerGetApplicationContext() *ApplicationContext

EagerGetApplicationContext returns the global ApplicationContext before it becomes available for dependency injection Important: packages should typically get ApplicationContext via fx's dependency injection,

which internal application config are guaranteed.
Only packages involved in priority bootstrap (appconfig, consul, vault, etc)
should use this function for logging purpose

func (*App) Run

func (app *App) Run()

type ApplicationConfig

type ApplicationConfig interface {
	Value(key string) interface{}
	Bind(target interface{}, prefix string) error
}

type ApplicationContext

type ApplicationContext struct {
	context.Context
	// contains filtered or unexported fields
}

ApplicationContext is a Context carries addition data for application. delegates all other context calls to the embedded Context.

func NewApplicationContext

func NewApplicationContext(opts ...ContextOption) *ApplicationContext

func (*ApplicationContext) Config

func (*ApplicationContext) Name

func (c *ApplicationContext) Name() string

func (*ApplicationContext) String

func (_ *ApplicationContext) String() string

*************************

context.Context Interface
*************************

func (*ApplicationContext) Value

func (c *ApplicationContext) Value(key interface{}) interface{}

type ApplicationProperties

type ApplicationProperties struct {
	Name     string            `json:"name"`
	Profiles ProfileProperties `json:"profiles"`
}

type Bootstrapper

type Bootstrapper struct {
	// contains filtered or unexported fields
}

Bootstrapper stores application configurations for bootstrapping

func GlobalBootstrapper

func GlobalBootstrapper() *Bootstrapper

GlobalBootstrapper returns globally configured Bootstrapper. This bootstrapper is the one that being used by Execute, any package-level function works against this instance

func NewBootstrapper

func NewBootstrapper() *Bootstrapper

NewBootstrapper create a new Bootstrapper. Note: "bootstrap" package uses Singleton patterns for application bootstrap. Calling this function directly is not recommended

This function is exported for test packages to use

func (*Bootstrapper) AddInitialAppContextOptions

func (b *Bootstrapper) AddInitialAppContextOptions(options ...ContextOption)

func (*Bootstrapper) AddOptions

func (b *Bootstrapper) AddOptions(options ...fx.Option)

func (*Bootstrapper) AddStartContextOptions

func (b *Bootstrapper) AddStartContextOptions(options ...ContextOption)

func (*Bootstrapper) AddStopContextOptions

func (b *Bootstrapper) AddStopContextOptions(options ...ContextOption)

func (*Bootstrapper) EnableCliRunnerMode

func (b *Bootstrapper) EnableCliRunnerMode(runnerProviders ...interface{})

EnableCliRunnerMode implements CliRunnerEnabler

func (*Bootstrapper) NewApp

func (b *Bootstrapper) NewApp(cliCtx *CliExecContext, priorityOptions []fx.Option, regularOptions []fx.Option) *App

func (*Bootstrapper) Register

func (b *Bootstrapper) Register(m *Module)

type BuildInfoMetadata

type BuildInfoMetadata struct {
	Version   string             `json:"version"`
	BuildTime time.Time          `json:"build-time"`
	Hash      string             `json:"hash"`
	Modules   ModuleBuildInfoMap `json:"modules,omitempty"`
}

func (*BuildInfoMetadata) ToMap

func (m *BuildInfoMetadata) ToMap() map[string]interface{}

type BuildInfoResolver

type BuildInfoResolver interface {
	Resolve() BuildInfoMetadata
}

type CliExecContext

type CliExecContext struct {
	Cmd                *cobra.Command
	ActiveProfiles     []string
	AdditionalProfiles []string
	ConfigSearchPaths  []string
	Debug              bool
	Args               []string
}

type CliOptions

type CliOptions func(cmd *cobra.Command)

type CliRunner

type CliRunner func(ctx context.Context) error

func (CliRunner) WithOrder

func (r CliRunner) WithOrder(order int) OrderedCliRunner

type CliRunnerEnabler

type CliRunnerEnabler interface {
	// EnableCliRunnerMode see bootstrap.EnableCliRunnerMode
	EnableCliRunnerMode(runnerProviders ...interface{})
}

type CliRunnerLifecycleHooks

type CliRunnerLifecycleHooks interface {
	Before(ctx context.Context, runner CliRunner) context.Context
	After(ctx context.Context, runner CliRunner, err error) context.Context
}

CliRunnerLifecycleHooks provide instrumentation around CliRunners

type CloudProperties

type CloudProperties struct {
	Gateway GatewayProperties `json:"gateway"`
}

type ContextOption

type ContextOption func(ctx context.Context) context.Context

type GatewayProperties

type GatewayProperties struct {
	Service string `json:"service"`
	Scheme  string `json:"scheme"`
	Host    string `json:"host"`
	Port    int    `json:"port"`
}

type Module

type Module struct {
	// Precedence basically govern the order or invokers between different Bootstrapper
	Name            string
	Precedence      int
	PriorityOptions []fx.Option
	Options         []fx.Option
}

func InitModule

func InitModule(cliCtx *CliExecContext, app *App) *Module

InitModule returns the module that would run with highest priority

func MiscModules

func MiscModules() []*Module

MiscModules returns the module that would run with various precedence

type ModuleBuildInfo

type ModuleBuildInfo struct {
	Path    string `json:"path"`
	Version string `json:"version"`
}

type ModuleBuildInfoMap

type ModuleBuildInfoMap map[string]ModuleBuildInfo

func (*ModuleBuildInfoMap) UnmarshalText

func (m *ModuleBuildInfoMap) UnmarshalText(text []byte) error

type OrderedCliRunner

type OrderedCliRunner struct {
	Precedence int
	CliRunner  CliRunner
}

func (OrderedCliRunner) Order

func (r OrderedCliRunner) Order() int

type ProfileProperties

type ProfileProperties struct {
	Active     utils.CommaSeparatedSlice `json:"active"`
	Additional utils.CommaSeparatedSlice `json:"additional"`
}

type Properties

type Properties struct {
	Application ApplicationProperties `json:"application"`
	Cloud       CloudProperties       `json:"cloud"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL