tests

# TaskManager

A lightweight, elegant task scheduler for Kotlin and Java with support for cron expressions, fixed-rate scheduling, and manual execution.

## Features

- ✅ **Simple API** - Minimal concepts, maximum clarity
- ✅ **Cron Support** - Full cron expression support via cron-utils
- ✅ **Fixed Rate & Delay** - Flexible scheduling options
- ✅ **Manual Execution** - Run tasks on-demand
- ✅ **Context Management** - Type-safe context injection
- ✅ **Lifecycle Hooks** - Task start/complete callbacks
- ✅ **Concurrency Control** - Allow or prevent concurrent executions
- ✅ **Java Friendly** - Builder pattern for Java users
- ✅ **Zero Dependencies** - Except cron-utils for cron parsing

## Quick Start

### Kotlin

```kotlin
val tasks = TaskManager {
    concurrency = 4
    context["db"] = database
}

// Heartbeat every 5 seconds
tasks.task("heartbeat", every = 5.seconds) {
    println("heartbeat")
}

// Cron task - every hour
tasks.task("cleanup", cron = "0 0 * * * ?") {
    val db = get<Database>("db")
    db.cleanup()
}

// Manual task
tasks.task("rebuild-index") {
    rebuildIndex()
}

tasks.start()

// Manually execute
tasks.run("rebuild-index")

tasks.shutdown()
```

### Java

```java
TaskManager tasks = TaskManager.builder()
    .concurrency(4)
    .putContext("db", database)
    .build();

// Heartbeat every 5 seconds
tasks.task("heartbeat", null, Duration.ofSeconds(5), false, ctx -> {
    System.out.println("heartbeat");
    return null;
});

// Cron task
tasks.task("cleanup", "0 0 * * * ?", null, false, ctx -> {
    Database db = ctx.get("db");
    db.cleanup();
    return null;
});

tasks.start();
tasks.shutdown(true);
```

## Installation

Add to your `build.gradle.kts`:

```kotlin
dependencies {
    implementation("com.taskmanager:taskmanager:1.0.0")
}
```

## Core Concepts

### 1. Task Registration

Register tasks with simple or advanced scheduling:

```kotlin
// Simple - Fixed rate
tasks.task("task1", every = 10.seconds) { }

// Simple - Cron
tasks.task("task2", cron = "0 * * * * ?") { }

// Simple - Manual only
tasks.task("task3") { }

// Advanced - Schedule object
tasks.task("task4", Schedule.WithInitialDelay(
    delay = 1.minutes,
    schedule = Schedule.FixedRate(5.seconds)
)) { }
```

### 2. Context Management

Inject and use context values:

```kotlin
val tasks = TaskManager {
    context["db"] = database
    context["config"] = config
}

tasks.task("process") {
    val db = get<Database>("db")              // Throws if not found
    val cache = getOrNull<Cache>("cache")     // Returns null if not found
    val timeout = getOrDefault("timeout", 30)  // Returns default if not found
    
    // Set task-local values
    set("processed", 100)
}
```

### 3. Lifecycle Management

```kotlin
val tasks = TaskManager {
    autoStart = false  // Don't start immediately
    
    onTaskStart = { event ->
        println("Starting ${event.taskName}")
        // Dynamically inject context
        event.context["timestamp"] = System.currentTimeMillis()
    }
    
    onTaskComplete = { exec ->
        if (exec.isSuccess) {
            println("${exec.taskName} took ${exec.duration}ms")
        } else {
            println("${exec.taskName} failed: ${exec.error}")
        }
    }
}

tasks.start()  // Start scheduling
tasks.shutdown(awaitTermination = true)  // Graceful shutdown
```

### 4. Task Control

```kotlin
tasks.enable("task1")   // Enable scheduling
tasks.disable("task1")  // Disable scheduling (doesn't affect running tasks)
tasks.remove("task1")   // Remove task completely

// Query
tasks.exists("task1")                  // Check existence
tasks.getTaskDefinition("task1")        // Get task metadata
tasks.listTaskNames()                   // List all tasks
```

### 5. Manual Execution

```kotlin
// Async execution
val future = tasks.run("task1")
val result = future.get()

// Sync execution
val result = tasks.runBlocking("task1")

// With additional context
tasks.run("task1", mapOf("param" to "value"))
```

### 6. Concurrency Control

```kotlin
// Don't allow concurrent execution (default)
tasks.task("exclusive", every = 5.seconds, allowConcurrent = false) {
    Thread.sleep(10000)  // Even if this takes longer, next execution waits
}

// Allow concurrent execution
tasks.task("parallel", every = 5.seconds, allowConcurrent = true) {
    Thread.sleep(10000)  // Multiple instances can run simultaneously
}
```

## Advanced Examples

### Custom Monitoring

```kotlin
class TaskMonitor {
    private val stats = ConcurrentHashMap<String, TaskStats>()
    
    data class TaskStats(
        var totalExecutions: Long = 0,
        var successCount: Long = 0,
        var failureCount: Long = 0,
        var averageDuration: Long = 0
    )
    
    fun record(execution: TaskExecution) {
        val stat = stats.getOrPut(execution.taskName) { TaskStats() }
        stat.totalExecutions++
        if (execution.isSuccess) stat.successCount++
        // ... update stats
    }
}

val monitor = TaskMonitor()

val tasks = TaskManager {
    onTaskComplete = { exec -> monitor.record(exec) }
}
```

### Dynamic Context Injection

```kotlin
val tasks = TaskManager {
    onTaskStart = { event ->
        // Inject context based on task type
        when {
            event.taskName.startsWith("db-") -> {
                event.context["connection"] = connectionPool.acquire()
            }
            event.taskName.startsWith("api-") -> {
                event.context["token"] = refreshToken()
            }
        }
    }
}
```

### Retry Logic

```kotlin
tasks.task("resilient-task") {
    retry(times = 3, delay = 5.seconds) {
        riskyOperation()
    }
}

// Helper function
fun <T> retry(times: Int, delay: Duration, block: () -> T): T {
    repeat(times - 1) {
        try {
            return block()
        } catch (e: Exception) {
            Thread.sleep(delay.toMillis())
        }
    }
    return block()  // Last attempt
}
```

## Schedule Types

```kotlin
// Cron expression (Quartz format)
Schedule.Cron("0 0 * * * ?")  // Every hour

// Fixed rate (from start time)
Schedule.FixedRate(Duration.ofSeconds(10))

// Fixed delay (from completion time)
Schedule.FixedDelay(Duration.ofSeconds(10))

// One-time execution
Schedule.Once(Instant.now().plusSeconds(60))

// With initial delay
Schedule.WithInitialDelay(
    delay = Duration.ofMinutes(1),
    schedule = Schedule.FixedRate(Duration.ofSeconds(5))
)
```

## Cron Expression Format

Uses Quartz cron format:

```
 ┌───────────── second (0-59)
 │ ┌───────────── minute (0-59)
 │ │ ┌───────────── hour (0-23)
 │ │ │ ┌───────────── day of month (1-31)
 │ │ │ │ ┌───────────── month (1-12 or JAN-DEC)
 │ │ │ │ │ ┌───────────── day of week (0-6 or SUN-SAT)
 │ │ │ │ │ │
 * * * * * *
```

Examples:
- `0 0 * * * ?` - Every hour at minute 0
- `0 */5 * * * ?` - Every 5 minutes
- `0 0 9-17 * * MON-FRI` - Every hour from 9am to 5pm, Monday to Friday
- `0 0 0 1 * ?` - First day of every month at midnight

## Configuration Options

```kotlin
TaskManagerConfig {
    // Number of threads in pool
    var concurrency: Int = Runtime.getRuntime().availableProcessors()
    
    // Thread name prefix
    var threadNamePrefix: String = "task-manager"
    
    // Auto-start scheduling on creation
    var autoStart: Boolean = false
    
    // Global context
    val context: MutableMap<String, Any>
    
    // Lifecycle hooks
    var onTaskStart: ((TaskStartEvent) -> Unit)? = null
    var onTaskComplete: ((TaskExecution) -> Unit)? = null
}
```

## Best Practices

1. **Use context for shared resources**: Database connections, configurations, etc.
2. **Implement monitoring via hooks**: Don't let the framework dictate your monitoring strategy
3. **Handle errors in tasks**: Wrap risky operations in try-catch
4. **Use allowConcurrent wisely**: Most tasks should not allow concurrent execution
5. **Graceful shutdown**: Always call `shutdown(awaitTermination = true)`
6. **Test cron expressions**: Use online tools to validate before deployment

## Thread Safety

- All public methods are thread-safe
- Context maps use `ConcurrentHashMap`
- Task execution is isolated
- Safe to call from multiple threads

## License

MIT License

## Credits

Built with:
- [cron-utils](https://github.com/jmrozanec/cron-utils) - Cron expression parsing