mx

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 0 Imported by: 0

README

MX

Go Reference Go Version Go Report Card License

A Go microservices framework with runtime launcher and services runner

Features

  • Logger
  • Launcher
  • Services
  • Services runner
  • Enabler interface
  • HealthChecker interface
  • Metrics
  • Health checker
  • Liveness probe (/livez)
  • Readiness probe (/readyz)
  • Ping pong service
  • Http transport
  • GRPC transport
  • GRPC client
  • ConnectRPC transport
  • ConnectRPC client

AI Agent Skills

This repository includes AI agent skills with documentation and usage examples for all packages. Install them with the skills CLI:

go install github.com/sxwebdev/skills/cmd/skills@latest
skills init
skills repo add tkcrm/mx

Launcher capabilities

Capability Option / Interface Description
Lifecycle hooks WithBeforeStart, WithAfterStart, WithBeforeStop, WithAfterStop Global hooks around app start/stop
Service state machine svc.State() Tracks each service: idle → starting → running → stopping → stopped / failed
Service restart policy WithRestartPolicy(RestartPolicy{...}) RestartOnFailure / RestartAlways with exponential backoff
Readiness signalling ReadinessReporter / WithReadiness(ch) Service reports when it is operational; gates startup-priority groups and WithStartupTimeout
Startup timeout WithStartupTimeout(d) Fail a readiness-reporting service if it does not become ready within d (no effect otherwise)
Shutdown timeout (per service) WithShutdownTimeout(d) Max time to wait for a service to stop
Global shutdown timeout WithGlobalShutdownTimeout(d) Hard deadline for the entire graceful shutdown phase
Startup priority WithStartupPriority(n) Group-based startup ordering: same priority starts concurrently, groups run in ascending order
Stop sequence WithRunnerServicesSequence(...) None (parallel) / Fifo / Lifo
Service lookup ServicesRunner().Get(name) Retrieve a registered service by name at runtime
Health checker types.HealthChecker interface Periodic per-service health check, polled on a configurable interval
Liveness probe ops /livez 200 healthy / 503 if any service is in Failed state
Readiness probe ops /readyz 200 ready / 424 starting / 503 failed — combines ServiceState + HealthChecker results
Legacy health endpoint ops /healthy Backward-compatible endpoint (HealthChecker results only)
Metrics ops /metrics Prometheus metrics endpoint
Profiler ops /debug/pprof Go pprof profiler endpoint

How to use

Repo with example

Init launcher
var version = "local"
var appName = "mx-example"

logger := logger.New(
    logger.WithAppVersion(version),
    logger.WithAppName(appName),
)

ln := launcher.New(
    launcher.WithName(appName),
    launcher.WithLogger(logger),
    launcher.WithVersion(version),
    launcher.WithContext(context.Background()),
    launcher.WithAfterStart(func() error {
        logger.Infoln("app", appName, "was started")
        return nil
    }),
    launcher.WithAfterStop(func() error {
        logger.Infoln("app", appName, "was stopped")
        return nil
    }),
)
Init and register custom service
// init
svc := launcher.NewService(
    launcher.WithServiceName("test-service"),
    launcher.WithStart(func(_ context.Context) error {
        return nil
    }),
    launcher.WithStop(func(_ context.Context) error {
        time.Sleep(time.Second * 3)
        return nil
    }),
)

// register in launcher
ln.ServicesRunner().Register(svc)
Init and register ping pong service
import "github.com/tkcrm/mx/launcher/services/pingpong"

// init
pingPongSvc := launcher.NewService(launcher.WithService(pingpong.New(logger)))

// register in launcher
ln.ServicesRunner().Register(pingPongSvc)
Register any service that implements IService

Any struct with Name(), Start(), and Stop() methods satisfies types.IService and can be wrapped with launcher.NewService:

import "github.com/tkcrm/mx/launcher/types"

type books struct {
    name       string
    hcInterval time.Duration
}

func New() *books {
    return &books{
        name:       "books-service",
        hcInterval: time.Second * 3,
    }
}

func (s books) Name() string { return s.name }

func (s books) Healthy(ctx context.Context) error { return nil }

func (s books) Interval() time.Duration { return s.hcInterval }

func (s books) Start(ctx context.Context) error {
    <-ctx.Done()
    return nil
}

func (s books) Stop(ctx context.Context) error { return nil }

var _ types.HealthChecker = (*books)(nil)
var _ types.IService = (*books)(nil)

func main() {
    ln := launcher.New()

    // register service in launcher with health checker
    ln.ServicesRunner().Register(
        launcher.NewService(
            launcher.WithService(New()),
        ),
    )
}
Startup priority

Services can be assigned a startup priority to control initialization order. Services with the same priority start concurrently within a group. Groups are started sequentially in ascending priority order. Priority 0 (default) services start last, concurrently, after all prioritized groups are ready.

"Ready" is reported by the service itself: implement mxtypes.ReadinessReporter (Ready() <-chan struct{}, close the channel once operational) or pass WithReadiness(ch). A service that does not report readiness is considered ready as soon as its Start goroutine is launched — so a priority-1 database only truly blocks the next group if it reports readiness. WithStartupTimeout(d) bounds the wait for that signal.

ln.ServicesRunner().Register(
    // Priority 1: DB layer — start concurrently, both must be ready before next group
    launcher.NewService(
        launcher.WithServiceName("postgres"),
        launcher.WithStartupPriority(1),
        launcher.WithService(pgService),
    ),
    launcher.NewService(
        launcher.WithServiceName("redis"),
        launcher.WithStartupPriority(1),
        launcher.WithService(redisService),
    ),
    // Priority 2: message broker — waits for DB layer to be ready
    launcher.NewService(
        launcher.WithServiceName("rabbitmq"),
        launcher.WithStartupPriority(2),
        launcher.WithService(rabbitService),
    ),
    // Priority 0 (default): application services — start concurrently after all groups
    launcher.NewService(
        launcher.WithServiceName("http-server"),
        launcher.WithService(httpService),
    ),
    launcher.NewService(
        launcher.WithServiceName("grpc-server"),
        launcher.WithService(grpcService),
    ),
)
// Start order: (postgres + redis) → rabbitmq → (http + grpc concurrently)
Graceful shutdown

The first signal (SIGTERM / SIGINT / SIGQUIT) starts a graceful shutdown. A second signal forces immediate exit.

if err := ln.Run(); err != nil {
    logger.Fatal(err)
}

Documentation

Overview

Package mx is a composable Go microservices framework built around a central Launcher that orchestrates independent services through a services runner.

MX gives every service a well-defined lifecycle (idle → starting → running → stopping → stopped/failed), graceful shutdown on OS signals, health checks, metrics, profiling, and ready-made HTTP/gRPC/ConnectRPC transports and clients.

Getting started

go get github.com/tkcrm/mx@latest

A minimal application wires a logger, registers services with the launcher, and blocks on Run:

l := logger.NewExtended(logger.WithAppName("app"))

ln := launcher.New(
	launcher.WithName("app"),
	launcher.WithVersion("v1.0.0"),
	launcher.WithLogger(l),
)

ln.ServicesRunner().Register(
	launcher.NewService(launcher.WithService(mySvc)),
)

if err := ln.Run(); err != nil { // blocks until shutdown
	log.Fatal(err)
}

Services

A service is any value implementing the github.com/tkcrm/mx/launcher/lntypes.IService interface (Name, Start, Stop). Start must block until its context is cancelled or its work is done. Wrap a service with github.com/tkcrm/mx/launcher.NewService and github.com/tkcrm/mx/launcher.WithService, which duck-types the value for the optional lntypes.Enabler and lntypes.HealthChecker interfaces as well.

Startup priority

Services are started in ascending startup-priority groups. All services in a group must become ready before the next group starts, while services within a group start concurrently. This lets infrastructure such as databases and message queues come up first, with the rest of the application starting only once they are ready. Priority 0 (the default) starts last, after every prioritized group is ready:

ln.ServicesRunner().Register(
	launcher.NewService(launcher.WithService(db), launcher.WithStartupPriority(1)),
	launcher.NewService(launcher.WithService(queue), launcher.WithStartupPriority(1)),
	launcher.NewService(launcher.WithService(app)), // priority 0 → starts last
)

"Ready" is what a service reports through the optional github.com/tkcrm/mx/mxtypes.ReadinessReporter interface (or the github.com/tkcrm/mx/launcher.WithReadiness option): a database becomes ready once it has connected, an HTTP server once it is listening. A service that does not report readiness is considered ready as soon as its Start goroutine is launched, so to truly gate a group behind infrastructure that service must report readiness. StartupTimeout bounds the wait for this signal.

Shutdown order is controlled independently via github.com/tkcrm/mx/launcher.WithRunnerServicesSequence (None/Fifo/Lifo).

Restart policies

Per-service restart behaviour is configured with github.com/tkcrm/mx/launcher.WithRestartPolicy: RestartOnFailure or RestartAlways, with a bounded number of retries and exponential backoff.

Ops

When ops are enabled via github.com/tkcrm/mx/launcher.WithOpsConfig, the launcher runs a dedicated HTTP server (default port 10000) exposing a liveness probe (/livez), a readiness probe (/readyz), a legacy health endpoint (/healthy), Prometheus metrics (/metrics), and the pprof profiler (/debug/pprof).

Subpackages

  • launcher — service orchestration, lifecycle, restart policies, ops wiring.
  • launcher/lntypes — core interfaces (IService, HealthChecker, Enabler, StateProvider) and ServiceState.
  • launcher/ops — health, metrics, and profiler operational services.
  • logger — structured logging backed by go.uber.org/zap.
  • transport/http_transport — net/http server as a managed service.
  • transport/grpc_transport — gRPC server with interceptors, health, reflection.
  • transport/connectrpc_transport — ConnectRPC (gRPC-compatible) server.
  • clients/grpc_client, clients/connectrpc_client — generic client factories.
  • util — assorted helpers (JSON, structs, files, timing).

All MX components follow the functional-options pattern (WithXxx). See the package-level documentation of each subpackage for details.

Directories

Path Synopsis
clients
grpc_client module
ops
ops
sentry module
transport
structs
original package located here https://github.com/mcuadros/go-lookup
original package located here https://github.com/mcuadros/go-lookup

Jump to

Keyboard shortcuts

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