Skip to content

BacoFoods/eggron

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Eggron

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.

Installation

go get github.com/BacoFoods/eggron

Quick Start

package 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)
    }
}

Usage

Basic Setup

Create a new Eggron instance and configure it:

e := eggron.New()

Registering Tasks

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
})

Task Handler Signature

All task handlers must follow this signature:

func(ctx context.Context, args ...string) error
  • ctx context.Context: Context for cancellation, timeouts, and passing values
  • args ...string: Command-line arguments passed to the task
  • error: Return an error if the task fails

Using Context

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 Mode

Enable debug output to see what's happening:

e.SetDebug(true)

Parse Command Line Arguments

Parse command-line arguments before running:

e.Parse()

Execute Tasks

Run the configured tasks:

if err := e.Run(); err != nil {
    log.Fatal(err)
}

Command Line Interface

Eggron supports several command-line modes:

Run All Tasks (Default)

./your-app
# or explicitly
./your-app run

Executes all registered tasks in the order they were registered.

List Available Tasks

./your-app list

Displays all registered task names.

Run Specific Task Only

./your-app only <task-name> [args...]

Executes only the specified task with optional arguments.

Examples:

# Run only the "greet" task
./your-app only greet

# Run "greet" task with arguments
./your-app only greet Alice

Advanced Usage

Simplified Global API

Eggron 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
}

Working with Context

The context parameter provides powerful capabilities for task management:

Timeouts and Cancellation

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())
    }
})

Passing Values via Context

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
}

Instance-based API

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)

Method Chaining

Eggron supports method chaining for clean configuration:

err := eggron.New().
    SetDebug(true).
    Register("build", buildTask).
    Register("test", testTask).
    Register("deploy", deployTask).
    Parse().
    Run()

Error Handling in Tasks

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
})

Execution Stats

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.

Finisher Callback

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.

Complex Task Example

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
})

About

Sequential task runner

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages