π Getting Started with TaskRunna
Build your first async batch processor in minutes
Welcome to TaskRunna! This guide will walk you through creating your first batch processing application using TaskRunna Framework.
π Prerequisites
- Java 17+ (OpenJDK recommended)
- Gradle 7.4+ or Maven 3.6+
- Kotlin 1.9.20+ (or Java 8+ if using Java)
β‘ Quick Setup
1. Add TaskRunna Dependency
**Gradle (Kotlin DSL):**repositories {
maven {
url = uri("https://maven.pkg.github.com/thisKK/taskrunna-framework")
credentials {
username = "your-github-username"
password = "your-github-token" // Personal access token with read:packages
}
}
}
dependencies {
implementation("com.taskrunna:taskrunna:1.1.2")
}
<repositories>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/thisKK/taskrunna-framework</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.taskrunna</groupId>
<artifactId>taskrunna</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
read:packages
permission.
π― Your First Batch Processor
Letβs create a simple batch processor that processes customer orders:
Step 1: Define Your Data Model
data class Order(
val id: String,
val customerId: String,
val amount: Double,
val status: String
)
Step 2: Create a Batch Iterator
import com.taskrunna.batch.BaseBatchIterator
class OrderIterator(private val repository: OrderRepository) : BaseBatchIterator<Order>() {
override fun loadNextBatch(afterCursor: String, batchSize: Int): List<Order> {
return repository.findPendingOrders(afterCursor, batchSize)
}
override fun extractCursorFrom(item: Order): String {
return item.id
}
}
Step 3: Create Your Batch Processor
import com.taskrunna.batch.BatchJobProcessor
import com.google.common.util.concurrent.ListenableFuture
import io.github.oshai.kotlinlogging.KotlinLogging
class OrderProcessor {
private val logger = KotlinLogging.logger {}
fun processOrders() {
val processor = BatchJobProcessor(
iterator = OrderIterator(orderRepository),
submitJob = { order -> processOrder(order) },
onSuccess = { order, result ->
logger.info { "Successfully processed order ${order.id}" }
markOrderComplete(order.id)
},
onFailure = { order, error ->
logger.error(error) { "Failed to process order ${order.id}" }
markOrderFailed(order.id, error.message)
},
logger = logger
)
processor.run()
}
private fun processOrder(order: Order): ListenableFuture<String> {
// Your async processing logic here
// e.g., send to Kafka, call external API, etc.
return someAsyncService.process(order)
}
}
Step 4: Run Your Processor
fun main() {
val orderProcessor = OrderProcessor()
orderProcessor.processOrders()
}
ποΈ Configuration Options
TaskRunna provides flexible configuration:
Batch Size Configuration
val processor = BatchJobProcessor(
iterator = OrderIterator(repository),
submitJob = { order -> processOrder(order) },
batchSize = 50, // Process 50 items at a time
maxConcurrency = 10, // Max 10 concurrent jobs
// ... other options
)
Thread Pool Configuration
val customExecutor = Executors.newFixedThreadPool(20)
val processor = BatchJobProcessor(
iterator = OrderIterator(repository),
submitJob = { order -> processOrder(order) },
executor = customExecutor, // Use custom thread pool
// ... other options
)
Error Handling
val processor = BatchJobProcessor(
iterator = OrderIterator(repository),
submitJob = { order -> processOrder(order) },
onSuccess = { order, result ->
// Handle successful processing
updateOrderStatus(order.id, "COMPLETED", result)
},
onFailure = { order, error ->
// Handle processing errors
updateOrderStatus(order.id, "FAILED", error.message)
// Optional: send to dead letter queue
deadLetterQueue.send(order, error)
}
)
π Adding Metrics (Optional)
For production monitoring, add Prometheus metrics:
import com.taskrunna.batch.metrics.PrometheusConfig
// Create metrics registry
val metrics = PrometheusConfig.createBatchMetrics("order_processor")
val processor = BatchJobProcessor(
iterator = OrderIterator(repository),
submitJob = { order -> processOrder(order) },
metrics = metrics, // Enable metrics collection
jobName = "order_processing",
// ... other options
)
See our Metrics Guide for complete monitoring setup.
β Testing Your Processor
Unit Testing
import org.junit.jupiter.api.Test
import io.mockk.mockk
import io.mockk.every
class OrderProcessorTest {
@Test
fun `should process orders successfully`() {
// Given
val mockRepository = mockk<OrderRepository>()
val orders = listOf(
Order("1", "customer1", 100.0, "PENDING"),
Order("2", "customer2", 200.0, "PENDING")
)
every { mockRepository.findPendingOrders(any(), any()) } returns orders
// When
val iterator = OrderIterator(mockRepository)
val batch = iterator.loadNextBatch("", 10)
// Then
assertEquals(2, batch.size)
assertEquals("1", iterator.extractCursorFrom(batch[0]))
}
}
π Next Steps
- Explore Examples - See real-world use cases
- Add Monitoring - Set up Prometheus metrics
- API Reference - Deep dive into all features
π Troubleshooting
Common Issues
Authentication Error with GitHub Packages:
Could not resolve com.taskrunna:taskrunna:1.1.2
Solution: Ensure your GitHub token has read:packages
permission and is correctly configured.
OutOfMemoryError:
java.lang.OutOfMemoryError: GC overhead limit exceeded
Solution: Reduce batchSize
or increase JVM heap space with -Xmx2g
.
Too Many Concurrent Requests:
Connection pool exhausted
Solution: Reduce maxConcurrency
parameter.
Getting Help
- π API Reference - Complete documentation
- π GitHub Issues - Report bugs
- π‘ Examples - More code samples
Ready to build something awesome? Letβs go! π