Documentation
¶
Overview ¶
Package fx is a modular service framework that makes it easy to create services and re-usable, composable modules.
Example ¶
package main import ( "context" "log" "net/http" "os" "time" "go.uber.org/fx" ) func NewLogger() *log.Logger { logger := log.New(os.Stdout, "[Example] " /* prefix */, 0 /* flags */) logger.Print("Executing NewLogger.") return logger } func NewHandler(logger *log.Logger) http.Handler { logger.Print("Executing NewHandler.") return http.HandlerFunc(func(http.ResponseWriter, *http.Request) { logger.Print("Got a request.") }) } func NewMux(lc fx.Lifecycle, logger *log.Logger) *http.ServeMux { logger.Print("Executing NewMux.") mux := http.NewServeMux() server := &http.Server{ Addr: ":8080", Handler: mux, } // If NewMux is called, we know that someone is using the mux. In that case, // start up and shut down an HTTP server with the application. lc.Append(fx.Hook{ OnStart: func(context.Context) error { logger.Print("Starting HTTP server.") go server.ListenAndServe() return nil }, OnStop: func(ctx context.Context) error { logger.Print("Stopping HTTP server.") return server.Shutdown(ctx) }, }) return mux } func Register(mux *http.ServeMux, h http.Handler) { mux.Handle("/", h) } func main() { app := fx.New( // Provide all the constructors we need. fx.Provide(NewLogger, NewHandler, NewMux), // Before starting, register the handler. This forces resolution of all // the types Register function depends on: *http.ServeMux and http.Handler. // Since the mux is now being used, its startup hook gets registered // and the application includes an HTTP server. fx.Invoke(Register), ) // In a real application, we could just use app.Run() here. Since we don't // want this example to run forever, we'll use Start and Stop. startCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := app.Start(startCtx); err != nil { log.Fatal(err) } // Normally, we'd block here with <-app.Done(). http.Get("http://localhost:8080/") stopCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := app.Stop(stopCtx); err != nil { log.Fatal(err) } }
Output: [Example] Executing NewLogger. [Example] Executing NewMux. [Example] Executing NewHandler. [Example] Starting HTTP server. [Example] Got a request. [Example] Stopping HTTP server.
Index ¶
Examples ¶
Constants ¶
const Version = "1.2.0"
Version is exported for runtime compatibility checks.
Variables ¶
var NopLogger = Logger(nopLogger{})
NopLogger disables the application's log output.
Functions ¶
This section is empty.
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
An App is a modular application built around dependency injection.
func New ¶
New creates and initializes an App. All applications begin with the Lifecycle type available in their dependency injection container.
It then executes all functions supplied via the Invoke option. Supplying arguments to these functions requires calling some of the constructors supplied by the Provide option. If any invoked function fails, an error is returned immediately.
func (*App) Err ¶
Err returns an error that may have been encountered during the graph resolution.
This includes things like incomplete graphs, circular dependencies, missing dependencies, invalid constructors, and invoke errors.
func (*App) Run ¶
func (app *App) Run()
Run starts the application, blocks on the signals channel, and then gracefully shuts the application down. It uses DefaultTimeout for the start and stop timeouts.
See Start and Stop for application lifecycle details.
func (*App) Start ¶
Start executes all the OnStart hooks of the resolved object graph in the instantiation order.
This typically starts all the long-running goroutines, like network servers or message queue consumers.
First, Start checks whether any errors were encountered while applying Options. If so, it returns immediately.
By taking a dependency on the Lifecycle type, some of the executed constructors may register start and stop hooks. After executing all Invoke functions, Start executes all OnStart hooks registered with the application's Lifecycle, starting with the root of the dependency graph. This ensures that each constructor's start hooks aren't executed until all its dependencies' start hooks complete. If any of the start hooks return an error, start short-circuits.
func (*App) Stop ¶
Stop gracefully stops the application. It executes any registered OnStop hooks in reverse order (from the leaves of the dependency tree to the roots), so that types are stopped before their dependencies.
If the application didn't start cleanly, only hooks whose OnStart phase was called are executed. However, all those hooks are always executed, even if some fail.
type Hook ¶
A Hook is a pair of start and stop callbacks, either of which can be nil. If a Hook's OnStart callback isn't executed (because a previous OnStart failure short-circuited application start), its OnStop callback won't be executed.
type In ¶
In can be embedded in a constructor's param struct in order to take advantage of named and optional types.
Modules should take a single param struct that embeds an In in order to provide a forwards-compatible API where additional optional fields can be added without breaking.
type Lifecycle ¶
type Lifecycle interface {
Append(Hook)
}
Lifecycle allows constructors to register callbacks that are executed on application start and stop.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
An Option configures an App.
func Extract ¶
func Extract(target interface{}) Option
Extract fills the given struct with values from the dependency injection container on application start.
The target MUST be a pointer to a struct. Only exported fields will be filled.
Example ¶
var target struct { Logger *log.Logger } app := New( Provide(func() *log.Logger { return log.New(os.Stdout, "", 0) }), Extract(&target), ) if err := app.Start(context.Background()); err != nil { log.Fatal(err) } target.Logger.Print("Extracted!")
Output: Extracted!
func Invoke ¶
func Invoke(funcs ...interface{}) Option
Invoke registers functions that are executed eagerly on application start. Arguments for these functions are provided from the application's dependency injection container.
Unlike constructors, invoked functions are always executed, and they're always run in order. Invoked functions may have any number of returned values. If the final returned object is an error, it's assumed to be a success indicator. All other returned values are discarded.
See the documentation for go.uber.org/dig for further details.
func Provide ¶
func Provide(constructors ...interface{}) Option
Provide registers constructors with the application's dependency injection container. Constructors provide one or more types, can depend on other types available in the container, and may optionally return an error. For example:
// Provides type *C, depends on *A and *B. func(*A, *B) *C // Provides type *C, depends on *A and *B, and indicates failure by // returning an error. func(*A, *B) (*C, error) // Provides type *B and *C, depends on *A, and can fail. func(*A) (*B, *C, error)
The order in which constructors are provided doesn't matter. Constructors are called lazily and their results are cached for reuse.
Taken together, these properties make it perfectly reasonable to Provide a large number of standard constructors even if only a fraction of them are used.
See the documentation for go.uber.org/dig for further details.