App
Application Startup
Trace how a GoLazy application is constructed and started.
Start from main
The executable entry point stays small:
func main() {
if err := appinit.App().ListenAndServe(); err != nil {
log.Fatal(err)
}
}
App() returns a fully constructed application. ListenAndServe starts the
HTTP server.
Construct the app
init/app.go calls lazyapp.New:
func App() *lazyapp.App {
return lazyapp.New(lazyapp.Config{
Name: "sample_app",
Drawer: Draw,
Public: app.Public,
Views: app.Views,
Dependencies: Dependencies,
})
}
That call initializes application dependencies, optional jobs, SEO defaults, the renderer, route scope, dispatcher, asset registry, helpers, and public asset fallback.
Initialize shared dependencies
Dependencies runs once during application construction:
func Dependencies(deps *lazydeps.Scope) error {
_, err := lazydeps.Service(deps, "helloworldservice", func(ctx context.Context) (
context.Context,
helloworldservice.Service,
error,
context.CancelFunc,
) {
service := helloworldservice.New()
return helloworldservice.WithContext(ctx, service), service, nil, nil
})
return err
}
Controllers resolve shared dependencies from this context during request-local construction.
Initialize background jobs
lazyapp.Config.Jobs runs after Dependencies with the dependency-initialized
app context. It creates a lazyjobs.JobRunner, registers the app's job
definitions, injects the runner into the app context, and starts in-process
workers:
func App() *lazyapp.App {
return lazyapp.New(lazyapp.Config{
Name: "sample_app",
Drawer: Draw,
Public: app.Public,
Views: app.Views,
Dependencies: Dependencies,
Jobs: lazyapp.Jobs(lazyjobs.Config{
Define: jobs.DefinedJobs,
}),
})
}
Read Background Jobs.
Initialize SEO defaults
lazyapp.Config.SEO runs after Dependencies, so application-wide metadata
defaults can read dependency-backed values from the app context:
func App() *lazyapp.App {
return lazyapp.New(lazyapp.Config{
Name: "sample_app",
Drawer: Draw,
Public: app.Public,
Views: app.Views,
Dependencies: Dependencies,
SEO: SEO,
})
}
Keep that function in init/seo.go. Read
SEO And Sitemaps.
Draw routes
The app passes a framework-created route scope to Draw:
func Draw(router *lazyroutes.Scope) {
router.Resources(homecontroller.New, func(home *lazyroutes.Resource) {
home.Singular("home")
home.Plural("home")
home.Path("")
})
}
Draw only registers routes. It does not create the mux, dispatcher, public
fallback, or server.
Choose the address
ListenAndServe reads ADDR, then PORT, then falls back to
127.0.0.1:3000:
ADDR=127.0.0.1:4000 ./sample-app
PORT=4000 ./sample-app
A numeric ADDR or PORT value is treated as a port. A full address is passed
to the underlying server.
CONTROL_PLANE_ADDR activates the default control plane during
ListenAndServe. If it matches the app address, probes are mounted into the app
server. If it differs, GoLazy starts a second server for the control plane.
The separate server automatically includes /debug/pprof/ and the standard
pprof subpaths.
If it is unset, production builds do not mount control-plane endpoints on the
public app listener.