Skip to content

lftk/ub

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ub

ub is a minimal bootstrapper for go.uber.org/fx that handles the application lifecycle for you.

Go Reference Go Report Card

Overview

go.uber.org/fx is a powerful dependency injection framework for Go. However, wiring up a long-running application (like a web server or a message queue consumer) into its lifecycle can be verbose. You typically need to manage fx.Lifecycle hooks, run your main logic in a separate goroutine to avoid blocking startup, and manually handle shutdown signals.

ub abstracts away all of this boilerplate. It provides a single function, ub.Run, that lets you focus on your application's core logic, while ub handles the rest.

Features

  • Zero Boilerplate: Run your long-running service with a single function call.
  • Full fx Integration: Built on top of fx, so you can use all of its features like dependency injection, modules, and more.
  • Graceful Shutdown: Automatically handles OS signals (e.g., Ctrl+C) and ensures your application shuts down gracefully.
  • Dependency Injection: Your main function's parameters are automatically supplied by the fx container.

Installation

go get github.com/lftk/ub

Usage

Here is a complete example of a simple HTTP server running with ub.

package main

import (
	"context"
	"errors"
	"fmt"
	"net/http"

	"github.com/lftk/ub"
	"go.uber.org/fx"
)

func main() {
	opts := []fx.Option{
		fx.NopLogger,
		// Provide the http.Handler dependency to the Fx container.
		fx.Provide(NewHandler),
	}
	// Run the application with our serve function.
	ub.Run(serve, opts...)
}

// serve is our main application logic.
// It receives the application context and any dependencies from Fx.
func serve(ctx context.Context, h http.Handler) error {
	// Create a new HTTP server.
	s := &http.Server{
		Addr:    "127.0.0.1:8080",
		Handler: h,
	}

	// Register a function to be called when the context is cancelled.
	// This is the key to graceful shutdown.
	context.AfterFunc(ctx, func() {
		// The context is cancelled, so we begin shutting down the server.
		// We use a background context for the shutdown process itself.
		_ = s.Shutdown(context.Background())
	})

	fmt.Println("HTTP server listening on", s.Addr)

	// Start the server. This is a blocking call.
	err := s.ListenAndServe()

	// ListenAndServe always returns an error. If it's ErrServerClosed,
	// it means the shutdown was graceful, so we treat it as success.
	if errors.Is(err, http.ErrServerClosed) {
		err = nil
	}

	return err
}

// NewHandler creates a new http.Handler.
// Fx will automatically call this function and provide its result
// to any other function that needs an http.Handler.
func NewHandler() http.Handler {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("Got a request.")
		fmt.Fprintln(w, "Hello, world!")
	})
	return mux
}

How It Works

You provide ub.Run with your main function (serve in the example above).

  1. The first argument of your function must be context.Context. ub will use this context to signal a graceful shutdown.
  2. Any other arguments are treated as dependencies that fx will provide.
  3. ub transparently creates an fx.Lifecycle hook that runs your function in the background.
  4. When your function returns, or when an OS signal is received, ub ensures the entire fx application shuts down gracefully.

License

MIT

About

ub is a minimal bootstrapper for go.uber.org/fx that handles the application lifecycle for you.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages