@RunnableAction
@RunnableAction registers a method under a name. Any code with access to the orchestrator can fire it by name — from a subscriber, a periodic loop, or onSafeLoop.
@RunnableAction("launch")
public void launch() {
orchestrator.publish("shooter/set/speed", 4800.0);
}
Fire it:
CompletableFuture<Void> done = orchestrator.runAction("launch");
Attributes
| Attribute | Type | Required | Meaning |
|---|---|---|---|
value | String | yes | the action name, e.g. @RunnableAction("launch"). |
Method signature rules
- No parameters. Actions take input through topics, not arguments.
- Returns
void. - Not static.
- Not repeatable — one method, one name.
Runtime behavior
- Fired by
orchestrator.runAction(name), which returns aCompletableFuture<Void>that completes when the method returns normally — chain with.thenRun(...)if you care about completion. - Runs on a dedicated, unbounded action pool, separate from the callback and scheduler pools, so a long action never blocks the bus.
- The action pool is not the hardware thread. An action that touches hardware must route the touch through
hardware.run(...)/device.run(...).
Error behavior
runAction completes exceptionally when:
- no action with that name is registered (
IllegalArgumentException), - the orchestrator is closed,
- or the action itself throws (the original exception is preserved on the future).
If the returned future is ignored, the failure is only visible in logs.
Gotchas
Action names are global. Two nodes registering
"fire"keep only the first; the second logs a warning and is skipped. Prefix action names with the subsystem:"shooter/launch".
cancelAllActions()is permanent. It shuts the action pool down for the rest of the OpMode — every laterrunActioncompletes exceptionally. Do not call it mid-OpMode expecting to re-enable actions.
Avoid long sleeps. An action that sleeps for a second occupies its pool thread for a second. That’s fine — the pool is unbounded — but prefer splitting long sequences into state published to topics, so other code can observe progress.
Next steps
@SubscribedTo— the event-driven form; most button presses become subscriptions, not actions.- Architecture — which pool runs what.