Concepts
The LittleHorse Quarkus extension uses annotations to declare tasks, workflows, structs, and user task forms. At startup, it discovers these types, registers them with the LittleHorse Kernel, and starts task workers.
Annotations
Tasks and Workflows
@LHTask: Marks a class as a LittleHorse task definition. Methods annotated with@LHTaskMethodbecome Task Workers.@LHWorkflow: Marks a method as a workflow definition. The method receives aWorkflowThreadand defines theWfSpec.@LHTaskMethod: Marks a method as the handler for a specificTaskDef.
Structs
@LHStructDef: Marks a class as a StructDef. Use it for typed, structured data in workflows and tasks.
Inline Structs
LittleHorse can embed an unannotated JavaBean as an inline schema instead of registering a named StructDef. See InlineStructDefs for guidance on choosing an embedded schema and details about its lifecycle and validation.
Use WorkflowThread#declareInlineStruct(String name, Class<?> type) for a workflow variable. For a task input or output, apply @LHType(isInlineStruct = true) to the parameter or method return type, respectively. The extension discovers types used in task signatures and registers them for native-image reflection, recursively including nested JavaBean properties, JavaBean array elements, and typed map values.
If the root JavaBean is referenced only by a workflow definition and never appears in a task signature or @LHStructDef, annotate it with @LHReflectiveType. The annotation recursively registers its nested JavaBean property types for reflection. Quarkus @RegisterForReflection remains available as a lower-level alternative. We hope to relax this @LHReflectiveType annotation requirement in LittleHorse 1.4, pending some SDK improvements.
User Tasks
@LHUserTaskForm: Marks a class as a User Task form definition. Use@UserTaskFieldon fields to define the form schema.
Registration
The extension scans your application for beans annotated with @LHTask, @LHWorkflow, @LHStructDef, and @LHUserTaskForm. It registers them with the LittleHorse Kernel at startup before the application is ready to serve requests.
You can disable registration globally or per-task, per-workflow, per-user-task, or per-struct via configuration. See Configuration.
Injected Clients
The extension provides two gRPC clients you can inject:
LittleHorseBlockingStub— For synchronous calls. Use it in REST endpoints, services, or any blocking code.LittleHorseReactiveStub— For reactive calls. Use it withUniandMultiin Quarkus reactive code.
Both clients use the same LittleHorse client configuration (environment variables, properties file, or LHConfig).
Hierarchical Workflows
You can define child workflows that run under a parent. Use the parent attribute of @LHWorkflow:
@LHWorkflow(PARENT_WF)
public void parent(WorkflowThread wf) {
wf.execute(GREETINGS_TASK, PARENT_WF, wf.declareStr(NAME_VARIABLE).asPublic());
}
@LHWorkflow(value = CHILD_WF, parent = PARENT_WF)
public void child(WorkflowThread wf) {
wf.execute(GREETINGS_TASK, CHILD_WF, wf.declareStr(NAME_VARIABLE).asInherited());
}
Retry Policies
Use @LHExponentialBackoffRetry as an attribute of @LHWorkflow to configure default retry behavior for task nodes. You can use config property placeholders:
@LHWorkflow(
value = "my-workflow",
defaultTaskExponentialBackoffRetry = @LHExponentialBackoffRetry(
baseIntervalMs = "${retry.base.interval.ms}",
maxDelayMs = "${retry.max.delay.ms}",
multiplier = "${retry.multiplier}"))
public void workflow(WorkflowThread wf) {
wf.execute("my-task", wf.declareStr("input").required());
}
Configure the values in application.properties:
retry.base.interval.ms=1000
retry.max.delay.ms=10000
retry.multiplier=2.0
StructDef Compatibility
When registering structs, you can control schema compatibility. See the structs configuration section.