Skip to content
/ mx Public

A Go application runtime launcher and services runner

License

Notifications You must be signed in to change notification settings

tkcrm/mx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MX

A Go microservices framework with runtime launcher and services runner

Features

  • Logger
  • Launcher
  • Services
  • Services runner
  • Service Enabler interface
  • Service HealthChecker interface
  • Metrics
  • Health checker
  • Ping pong service
  • Http transport
  • GRPC transport
  • GRPC client
  • ConnectRPC transport
  • ConnectRPC client
  • Config loader

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 := service.New(
    service.WithName("test-service"),
    service.WithStart(func(_ context.Context) error {
        return nil
    }),
    service.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

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

// register in launcher
ln.ServicesRunner().Register(pingPongSvc)

You can also register any service that implements the following interface

type IService interface {
    Name() string
    Start(ctx context.Context) error
    Stop(ctx context.Context) error
}

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 _ service.HealthChecker = (*books)(nil)

var _ service.IService = (*books)(nil)

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

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

Start launcher and all services with graceful shutdown

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

Config loader

type Config struct {
    ServiceName string            `default:"mx-example" validate:"required"`
    Prometheus  prometheus.Config
    Ops         ops.Config
    Grpc        grpc_transport.Config
}

conf := new(Config)
if err := cfg.Load(conf); err != nil {
    logger.Fatalf("could not load configuration: %s", err)
}