Advanced Guide
Startup Hooks
GoFr provides a way to run synchronous jobs when your application starts, before any servers begin handling requests. This is useful for tasks like seeding a database, warming up a cache, or performing other critical setup procedures.
OnStart
You can register a startup hook using the a.OnStart() method on your app instance.
Usage
The method accepts a function with the signature:
The method accepts a function with the signature func(ctx *gofr.Context) error.
- The
*gofr.Contextpassed to the hook is fully initialized and provides access to all dependency-injection-managed services (e.g.,ctx.Container.SQL,ctx.Container.Redis). - If any
OnStarthook returns an error, the application will log the error and refuse to start.
What "refuse to start" does
A hook that returns an error abandons the run, and the process exits with status 1.
- The error is logged.
- Everything startup has already opened is released — the container's datasources are live by the time hooks run, so they are closed rather than left to process exit.
- No server is started, and
app.Run()does not return.
Two consequences worth planning for:
- Code after
app.Run()inmaindoes not execute on this path.Runis meant to be the last call inmain; anything you need to happen on a failed start belongs in the hook itself or in anOnShutdownhook. - A test that calls
app.Run()with a failing hook terminates the test binary. Exercise the hook function directly rather than throughRun.
Exiting non-zero is deliberate: a Kubernetes restartPolicy, a CrashLoopBackOff and a systemd restart all need a non-zero status. A service that refused to start but reported success is the failure this avoids.
Example: Warming up a Cache
Here is an example of using OnStart to set an initial value in a Redis cache when the application starts.
package main
import (
"gofr.dev/pkg/gofr"
)
func main() {
a := gofr.New()
// Register an OnStart hook to warm up a cache.
a.OnStart(func(ctx *gofr.Context) error {
ctx.Logger.Info("Warming up the cache...")
// In a real app, this might come from a database or another service.
cacheKey := "initial-data"
cacheValue := "This is some data cached at startup."
err := ctx.Redis.Set(ctx, cacheKey, cacheValue, 0).Err()
if err != nil {
ctx.Logger.Errorf("Failed to warm up cache: %v", err)
return err // Return the error to halt startup if caching fails.
}
ctx.Logger.Info("Cache warmed up successfully!")
return nil
})
// ... register your routes
a.Run()
}
This ensures that critical startup tasks are completed successfully before the application begins accepting traffic.
Related production guides
- Graceful Shutdown: Mirror your startup work on the way down — close pools, drain queues, and finish in-flight requests cleanly.