A simple and flexible task runner library for Go applications. Eggron allows you to register and execute tasks with command-line interface support. Eggron is designed to run multiple tasks sequentially with a single cron execution.
go get github.com/BacoFoods/eggronpackage main
import (
"context"
"fmt"
"log"
"github.com/BacoFoods/eggron"
)
func main() {
// Simple API using global functions
eggron.Register("hello", func(ctx context.Context, args ...string) error {
fmt.Println("Hello, World!")
return nil
})
eggron.Register("greet", func(ctx context.Context, args ...string) error {
name := "World"
if len(args) > 0 {
name = args[0]
}
fmt.Printf("Hello, %s!\n", name)
return nil
})
err := eggron.Parse().SetDebug(true).Run()
if err != nil {
log.Fatal(err)
}
}Create a new Eggron instance and configure it:
e := eggron.New()Register tasks using the Register method. Tasks are functions that accept a context and optional arguments:
// Using instance method
e.Register("task-name", func(ctx context.Context, args ...string) error {
// Your task logic here
fmt.Printf("Executing task with args: %v\n", args)
return nil
})
// Using global function (simplified API)
eggron.Register("task-name", func(ctx context.Context, args ...string) error {
// Your task logic here
fmt.Printf("Executing task with args: %v\n", args)
return nil
})All task handlers must follow this signature:
func(ctx context.Context, args ...string) errorctx context.Context: Context for cancellation, timeouts, and passing valuesargs ...string: Command-line arguments passed to the taskerror: Return an error if the task fails
The context parameter allows you to:
- Handle cancellation and timeouts
- Pass values between tasks
- Implement graceful shutdowns
eggron.Register("timeout-task", func(ctx context.Context, args ...string) error {
select {
case <-time.After(5 * time.Second):
fmt.Println("Task completed")
return nil
case <-ctx.Done():
return ctx.Err() // Handle cancellation
}
})Enable debug output to see what's happening:
e.SetDebug(true)Parse command-line arguments before running:
e.Parse()Run the configured tasks:
if err := e.Run(); err != nil {
log.Fatal(err)
}Eggron supports several command-line modes:
./your-app
# or explicitly
./your-app runExecutes all registered tasks in the order they were registered.
./your-app listDisplays all registered task names.
./your-app only <task-name> [args...]Executes only the specified task with optional arguments.
# Run only the "greet" task
./your-app only greet
# Run "greet" task with arguments
./your-app only greet AliceEggron now provides a simplified API using global functions for common use cases:
package main
import (
"context"
"fmt"
"github.com/BacoFoods/eggron"
)
func main() {
// Register tasks using global functions
eggron.Register("build", buildTask)
eggron.Register("test", testTask)
// Parse and run with simplified API
err := eggron.Parse().SetDebug(true).Run()
if err != nil {
log.Fatal(err)
}
}
func buildTask(ctx context.Context, args ...string) error {
fmt.Println("Building application...")
// Check for cancellation
if ctx.Err() != nil {
return ctx.Err()
}
return nil
}The context parameter provides powerful capabilities for task management:
eggron.Register("long-task", func(ctx context.Context, args ...string) error {
// Create a timeout context
timeoutCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
select {
case <-time.After(10 * time.Second):
fmt.Println("Task completed successfully")
return nil
case <-timeoutCtx.Done():
return fmt.Errorf("task timed out: %w", timeoutCtx.Err())
}
})type contextKey string
const userIDKey contextKey = "userID"
// Set context values before running
func main() {
ctx := context.WithValue(context.Background(), userIDKey, "user123")
eggron.Register("user-task", userTask)
err := eggron.Parse().RunWithContext(ctx)
if err != nil {
log.Fatal(err)
}
}
func userTask(ctx context.Context, args ...string) error {
userID := ctx.Value(userIDKey).(string)
fmt.Printf("Processing for user: %s\\n", userID)
return nil
}For more complex scenarios, use the instance-based API:
e := eggron.New().
SetDebug(true).
Register("task1", task1Handler).
Register("task2", task2Handler)
// Custom context with values
ctx := context.WithValue(context.Background(), "key", "value")
err := e.Parse().RunWithContext(ctx)Eggron supports method chaining for clean configuration:
err := eggron.New().
SetDebug(true).
Register("build", buildTask).
Register("test", testTask).
Register("deploy", deployTask).
Parse().
Run()Tasks should return errors for proper error handling:
e.Register("failing-task", func(s *eggron.Shelf, args ...string) error {
if someCondition {
return fmt.Errorf("task failed: %s", reason)
}
return nil
})Both Run and RunOnly track execution statistics via EggStats. Each task execution produces an ExecutionStat containing the task name, success status, error (if any), and start/end times.
type EggStats struct {
Executions []ExecutionStat `json:"executions"`
}
type ExecutionStat struct {
Name string `json:"name"`
Success bool `json:"success"`
Error *string `json:"error,omitempty"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
}When using Run, all tasks execute even if one fails or panics. Errors are collected and returned as a combined error via WrapErrors. Panics are recovered automatically and recorded as errors in the stats.
Use SetFinisher to register a callback that runs after task execution completes. The finisher receives the EggStats for the run, allowing you to log results, send metrics, or trigger alerts.
eggron.SetFinisher(func(stats eggron.EggStats) {
for _, exec := range stats.Executions {
if exec.Success {
fmt.Printf("✓ %s (%s)\n", exec.Name, exec.EndTime.Sub(exec.StartTime))
} else {
fmt.Printf("✗ %s — error: %s\n", exec.Name, *exec.Error)
}
}
})
eggron.Register("build", buildTask)
eggron.Register("test", testTask)
err := eggron.Parse().Run()The finisher is called for both run (all tasks) and only (single task) commands, and is invoked regardless of whether tasks succeeded or failed.
eggron.Register("deploy", func(ctx context.Context, args ...string) error {
environment := "staging"
if len(args) > 0 {
environment = args[0]
}
fmt.Printf("Deploying to %s environment...\n", environment)
// Check for cancellation before starting
if ctx.Err() != nil {
return ctx.Err()
}
// Your deployment logic here
if err := deployTo(ctx, environment); err != nil {
return fmt.Errorf("deployment failed: %w", err)
}
fmt.Println("Deployment successful!")
return nil
})