fx

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 6, 2017 License: MIT Imports: 15 Imported by: 0

README

🦄 Fx GoDoc Github release Build Status Coverage Status Go Report Card

An application framework for Go that:

  • Makes dependency injection easy.
  • Eliminates the need for global state and func init().

Installation

We recommend locking to SemVer range ^1 using Glide:

glide get 'go.uber.org/fx#^1'

Stability

This library is v1 and follows SemVer strictly.

No breaking changes will be made to exported APIs before v2.0.0.

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

View Source
const Version = "1.2.0"

Version is exported for runtime compatibility checks.

Variables

View Source
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

func New(opts ...Option) *App

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) Done

func (app *App) Done() <-chan os.Signal

Done returns a channel of signals to block on after starting the application.

func (*App) Err

func (app *App) Err() error

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

func (app *App) Start(ctx context.Context) error

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

func (app *App) Stop(ctx context.Context) error

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

type Hook struct {
	OnStart func(context.Context) error
	OnStop  func(context.Context) error
}

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

type In struct{ dig.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 Logger

func Logger(p Printer) Option

Logger redirects the application's log output to the provided printer.

func Options

func Options(opts ...Option) Option

Options composes a collection of Options into a single Option.

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.

type Out

type Out struct{ dig.Out }

Out can be embedded in return structs in order to provide named types.

Modules should return a single results struct that embeds an Out in order to provide a forwards-compatible API where additional types can be provided over time without breaking.

type Printer

type Printer interface {
	Printf(string, ...interface{})
}

Printer is the interface required by fx's logging backend. It's implemented by most loggers, including the standard library's.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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