Skip to main content

Quickstart

View Markdown

Prerequisites: JDK 25, the lertha CLI, and a running orchestrator. For a laptop, the fastest orchestrator is the throwaway one the CLI ships:

lertha dev

That gives you an orchestrator on localhost:7233 and a UI on localhost:8233. In production the address is the Lertha orchestrator's; see Configuration.

1. Define a task​

data class GreetingInput(val greeting: String, val name: String)
data class Greeting(val text: String)

object GreetingTask : TaskHandler<GreetingInput, Greeting> {
override val type = taskType<GreetingInput, Greeting>("ComposeGreeting")

override suspend fun handle(input: GreetingInput, ctx: TaskContext): Greeting =
Greeting("${input.greeting}, ${input.name}!")
}

No annotations, no engine imports. The type name is what the UI and the CLI show.

2. Run a worker​

fun main() {
EngineConnection.fromEnvironment().use { connection ->
connection.runner("lab").use { runner ->
runner.register(GreetingTask)
runner.start()
Thread.currentThread().join()
}
}
}

3. Start the task from application code​

fun main(args: Array<String>) = runBlocking {
EngineConnection.fromEnvironment().use { connection ->
val orchestrator = connection.orchestrator()
val options = RunOptions(
id = "greeting-${UUID.randomUUID()}",
queue = "lab",
attemptTimeout = 10.seconds,
retry = RetryPolicy(maxAttempts = 5, initialInterval = 500.milliseconds),
)
val greeting = orchestrator.run(GreetingTask.type, GreetingInput("Hello", "World"), options)
println(greeting.text)
}
}

run is start followed by result(). Use start when the caller should not wait.

4. Reach the same worker from the CLI​

Because the handler registers under its plain type name:

lertha task run --type ComposeGreeting --id cli-1 --queue lab --timeout 10s \
--input '{"greeting":"Hello","name":"CLI"}'

Next​

  • Make it fail on purpose and watch the retries in the UI: Tasks.
  • Put a loop and a human around it: Flows.
  • The lab repository lerta-orchestration-lab has all of this wired, with a --fail N flag.