task/README.md
Jeremy Tregunna 43ad445ef5
All checks were successful
Go Tests / Run Tests (1.24.2) (push) Successful in 19s
feat: implement task dependency support with ordering verification
2025-04-18 13:45:37 -06:00

205 lines
5.1 KiB
Markdown

# Task
A simple and efficient scheduled task execution library for Go applications.
## Overview
The Task library provides a lightweight mechanism for scheduling and executing tasks with configurable intervals and rate limiting. It's particularly useful for applications that need to run background jobs, periodic maintenance tasks, or any recurring operations.
## Features
- Schedule tasks to run at regular intervals
- Rate limiting to control concurrent task execution
- Run tasks immediately (zero interval)
- Simple interface-based design for easy integration
- Task dependencies - tasks only run after their dependencies complete successfully
## Installation
```
go get git.canoozie.net/jer/task
```
## Usage
### Basic Example
```go
package main
import (
"fmt"
"time"
"git.canoozie.net/jer/task"
)
// Define a task by implementing the Task interface
type MyTask struct {
TaskID string
Name string
Dependencies []string
}
func (t *MyTask) ID() string {
return t.TaskID
}
func (t *MyTask) Execute() error {
fmt.Printf("Executing task: %s\n", t.Name)
return nil
}
func (t *MyTask) Dependencies() []string {
return t.Dependencies
}
func main() {
// Create a task executor with a rate limit of 2 concurrent tasks
executor := task.NewTaskExecutor(2)
// Create tasks with dependencies
task1 := &MyTask{
TaskID: "task1",
Name: "Database Initialization",
Dependencies: []string{},
}
task2 := &MyTask{
TaskID: "task2",
Name: "Data Processing",
Dependencies: []string{"task1"}, // Depends on task1
}
task3 := &MyTask{
TaskID: "task3",
Name: "Report Generation",
Dependencies: []string{"task2"}, // Depends on task2
}
// Add tasks - order doesn't matter, dependencies control execution order
executor.AddTask(task3, 0) // Will only run after task2 completes
executor.AddTask(task2, 0) // Will only run after task1 completes
executor.AddTask(task1, 0) // Will run immediately
// Start the task executor
executor.Start()
// Keep the program running
select {}
}
```
### Rate Limiting
The task executor includes built-in rate limiting to control how many tasks can run concurrently. This is useful for resource-intensive tasks or when you need to limit API calls.
```go
// Create an executor that allows up to 5 concurrent tasks
executor := task.NewTaskExecutor(5)
```
### Task Dependencies
Tasks can specify other tasks as dependencies, ensuring they only run after all their dependencies have completed successfully:
```go
// Task2 depends on Task1 - it won't run until Task1 completes successfully
task1 := &MyTask{
TaskID: "database-init",
Dependencies: []string{},
}
task2 := &MyTask{
TaskID: "data-processing",
Dependencies: []string{"database-init"},
}
// If Task1 fails, Task2 will not run
```
Key aspects of the dependency system:
- Dependencies are specified by task ID
- A task will only run when all its dependencies have completed successfully
- If a dependency fails, dependent tasks will not run
- Circular dependencies are automatically detected and rejected
- Self-dependencies are automatically detected and rejected
- Missing dependencies are silently allowed (developer's responsibility)
- Adding tasks in dependency order is not required - the system resolves the correct execution order
### Task Interface
To create a task, implement the `Task` interface:
```go
type Task interface {
ID() string
Execute() error
Dependencies() []string
}
```
- `ID()` - Returns a unique identifier for this task
- `Execute()` - Performs the task's operation, returning any errors
- `Dependencies()` - Returns a list of task IDs that must complete successfully before this task can run
Any errors returned from `Execute()` will be logged and will prevent dependent tasks from running.
## API Reference
### Types
#### `Task`
```go
type Task interface {
ID() string
Execute() error
Dependencies() []string
}
```
### Functions
#### `NewTaskExecutor`
```go
func NewTaskExecutor(rateLimit int) *TaskExecutor
```
Creates a new task executor with the specified concurrency limit.
### Methods
#### `AddTask`
```go
func (te *TaskExecutor) AddTask(task Task, interval time.Duration)
```
Schedules a task to run at the specified interval. If interval is 0, the task is executed immediately. Negative intervals are ignored.
#### `Start`
```go
func (te *TaskExecutor) Start()
```
Starts the task executor, which will begin processing scheduled tasks.
#### `Len`
```go
func (te *TaskExecutor) Len() int
```
Returns the number of tasks managed by the executor.
## License
Copyright (C) 2025 Jeremy Tregunna
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.