Application Lifecycle

Nimbus follows a Laravel-inspired boot sequence. Understanding the lifecycle helps you know where to put configuration, middleware, routes, and plugin setup.

Entry point: main.go

main.go is the minimal bootstrap. It delegates everything to bin/server.go:

package main

import "myapp/bin"

func main() {
    app := bin.Boot()
    _ = app.Run()
}

Boot sequence: bin/server.go

package bin

import (
    "github.com/CodeSyncr/nimbus"
    "github.com/CodeSyncr/nimbus/database"
    "myapp/config"
    "myapp/start"
)

func Boot() *nimbus.App {
    config.Load()
    app := nimbus.New()

    // Register plugins
    app.Use(
        stripe.New(),
        analytics.New(),
    )

    start.RegisterMiddleware(app)
    start.RegisterRoutes(app)
    _, _ = database.Connect(config.Database.Driver, config.Database.DSN)

    return app
}

What app.Run() does

When you call app.Run(), Nimbus executes the full lifecycle sequence:

app.Run()
  โ”œโ”€ configureGOGCFromEnv()
  โ”œโ”€ startPprofIfEnabled()
  โ”œโ”€ app.WarmUp()                       โ€” assembles app (idempotent)
  โ”‚    โ””โ”€ app.Boot()
  โ”‚         1. Provider.Register()      โ€” all providers bind services
  โ”‚         2. Plugin.Register()        โ€” all plugins
  โ”‚            โ””โ”€ HasBindings applied   โ€” container bindings registered
  โ”‚         3. Plugin.DefaultConfig     โ€” default configs collected
  โ”‚         4. Provider.Boot()          โ€” all providers resolve deps
  โ”‚         5. Plugin.Boot()            โ€” all plugins initialise
  โ”‚         6. Plugin capabilities:
  โ”‚            โ”œโ”€ HasRoutes             โ†’ routes mounted on router
  โ”‚            โ”œโ”€ HasMiddleware         โ†’ named middleware merged
  โ”‚            โ”œโ”€ HasCommands           โ†’ CLI commands registered
  โ”‚            โ”œโ”€ HasSchedule           โ†’ tasks added to scheduler
  โ”‚            โ”œโ”€ HasEvents             โ†’ listeners registered on event bus
  โ”‚            โ””โ”€ HasHealthChecks       โ†’ checks added to health checker
  โ”‚         7. App-level boot hooks     โ†’ OnBoot callbacks
  โ”‚    โ””โ”€ Warmup hooks                  โ†’ OnWarmup callbacks
  โ”‚    โ””โ”€ Dispatch events.AppWarmed     โ†’ payload: *App
  โ”œโ”€ Start hooks                        โ†’ OnStart callbacks
  โ”œโ”€ Scheduler.Start()                  โ†’ if tasks registered
  โ”œโ”€ ListenAndServe()                   โ†’ accept connections
  โ””โ”€ Dispatch events.AppReady           โ†’ payload: port

Shutdown (SIGINT/SIGTERM):
  โ””โ”€ Server.Shutdown(ctx)               โ†’ graceful drain
  โ””โ”€ Scheduler.Stop()                   โ†’ cancel background tasks
  โ””โ”€ HasShutdown.Shutdown()             โ†’ each plugin (reverse order; skipped in ModeWarmup)
  โ””โ”€ OnShutdown hooks                   โ†’ app-level cleanup

Functional Constructor Options

Configure your Nimbus application cleanly at initialization time using functional options:

// Create an app tailored for warmup or testing
app := nimbus.New(
    nimbus.WithMode(nimbus.ModeWarmup),
    nimbus.WithPort("8080"),
)

Warmup & Route Tooling

The WarmUp() phase assembles and boots the application without starting the HTTP listener, queue workers, or background crons. This is ideal for reading routes for client codegen, inspecting container bindings, or running tests.

app := bin.Boot()
app.SetMode(nimbus.ModeWarmup)

// Assembles providers, plugins, routes, and middleware
if err := app.WarmUp(); err != nil {
    log.Fatal(err)
}

// Programmatic route manifest generation (defaults to .nimbus-client)
if err := app.DumpRoutes(".nimbus-client"); err != nil {
    log.Fatal(err)
}

Application Modes

Nimbus applications run in one of four modes:

  • nimbus.ModeRun (default) โ€” Full application runtime including HTTP server and schedulers.
  • nimbus.ModeWarmup โ€” Inspection-only mode. app.Run() will reject execution, and plugin shutdown hooks are skipped.
  • nimbus.ModeTest โ€” Tailored for HTTP and integration testing.
  • nimbus.ModeCli โ€” For artisan-style CLI command execution.

Lifecycle hooks

Register callbacks at specific points in the lifecycle:

// After providers/plugins have booted, before warmup completes
app.OnBoot(func(a *nimbus.App) {
    log.Println("App booted with", len(a.Plugins()), "plugins")
})

// During the WarmUp phase, after boot and before start
app.OnWarmup(func(a *nimbus.App) {
    log.Println("App warmed up in mode:", a.GetMode())
})

// Right before the HTTP server begins serving
app.OnStart(func(a *nimbus.App) {
    log.Println("Server starting on port", a.Config.App.Port)
})

// During graceful shutdown
app.OnShutdown(func(a *nimbus.App) {
    log.Println("Cleaning up resources...")
})

Runtime configuration

  • NIMBUS_GOGC โ€” GC aggressiveness (50=aggressive, 100=default, 200=fewer cycles, off=disabled)
  • NIMBUS_PPROF โ€” enable pprof server (e.g. :6060 or 127.0.0.1:6060)

Request lifecycle

incoming request
  โ†’ server middleware (Logger, Recover, etc.)
  โ†’ route match
  โ†’ group middleware
  โ†’ named middleware (if assigned)
  โ†’ handler(ctx *http.Context) error
  โ†’ response