Handling Messages
This guide shows you how to write message handlers - the methods where all your business logic executes in a Talon microservice.
Required Reading: Before writing message handlers, you must read Programming Fundamentals. This page covers essential rules about message immutability, single-threaded store access, and Event Sourcing determinism requirements that all handler code must follow.
Overview
Message handlers are annotated methods that process inbound messages. When a message arrives, the AEP Engine dispatches it to the appropriate handler where your business logic executes. The handler reads data from the inbound message, updates the microservice store, and sends outbound messages.
Writing a Message Handler
Here's a canonical message handler that demonstrates the key elements:
@AppHAPolicy(HAPolicy.EventSourcing)
public class OrderProcessor {
// Injected by the platform
private AepMessageSender messageSender;
// Application-owned store (POJOs)
private Map<String, Order> orders = new HashMap<>();
@AppInjectionPoint
public void setMessageSender(AepMessageSender messageSender) {
this.messageSender = messageSender;
}
/**
* Message handler for new order messages
*/
@EventHandler
public void onNewOrder(NewOrderMessage message) {
// 1. Read data from inbound message
String orderId = message.getOrderId();
String symbol = message.getSymbol();
int quantity = message.getQuantity();
// 2. Read and update microservice store (POJOs)
Order order = orders.get(orderId);
if (order == null) {
order = new Order();
order.setOrderId(orderId);
orders.put(orderId, order);
}
order.setSymbol(symbol);
order.setQuantity(quantity);
order.setStatus("PENDING");
// 3. Create and send outbound message
OrderAckMessage ack = OrderAckMessage.create();
ack.setOrderId(orderId);
ack.setStatus("ACCEPTED");
ack.setTimestamp(System.currentTimeMillis());
messageSender.sendMessage("order-acks", ack);
// 4. Handler returns - transaction commits
// The AEP Engine will:
// - Replicate inbound message to backup instances
// - Backup replays message to rebuild store
// - Establish consensus with cluster members
// - Commit the transaction
// - Send the outbound message
// - Acknowledge the inbound message
}
}Handler Signature
A message handler must have this signature:
Key points:
Annotated with
@EventHandlerMust be
publicReturn type must be
voidTakes exactly one parameter - the inbound message
The message parameter type determines which messages this handler processes
Handler Method Names
Method names are not significant - the handler is matched to messages by the parameter type. However, following a naming convention like onMessageType makes code more readable.
Multiple Handlers for Same Message Type
You can have multiple handlers for the same message type:
Both handlers will be invoked for each NewOrderMessage. The order of invocation is deterministic but should not be relied upon - handlers should be independent.
Reading Inbound Messages
Access message fields using the generated getter methods:
Important: Inbound messages are read-only. See Programming Fundamentals for rules about message immutability and lifecycle.
Accessing Microservice Store
With Event Sourcing, your microservice store consists of POJOs that you manage directly. The store is private to your application and transparent to the Talon runtime:
Key points:
Store is your own POJOs, not ADM-generated
Consensus established by replaying inbound messages on backup instances
Store rebuilt on backup by replaying events
Your business logic must be deterministic
Store access rules:
Store can only be accessed from within a message handler (on the dispatch thread)
Store changes must be deterministic - no reliance on external state like system time or random numbers
See Programming Fundamentals for threading restrictions
See Event Sourcing Template for determinism requirements
Sending Outbound Messages
Create and send messages using the AepMessageSender:
When messages are sent: Outbound messages are not immediately sent when you call sendMessage(). Instead:
The message is queued
The handler returns
The inbound message is replicated to backup instances
Backup instances replay the message to rebuild store
Consensus is established
The transaction commits
Then the outbound message is sent
This ensures that messages are only sent if the transaction succeeds, providing exactly-once semantics.
See Sending Messages for details on message keys, channels, and unsolicited sends.
Transaction Lifecycle
When a message handler executes, it runs within a transaction:
For details on how consensus works, see Cluster Consensus.
For advanced transaction control, see Controlling Transactions.
Common Patterns
Pattern: Lookup or Create
Pattern: Conditional Send
Pattern: Aggregate and Send
Pattern: Forwarding Messages
You cannot resend an inbound message directly. To forward a message, copy it first:
See Programming Fundamentals for details.
Advanced Topics
Using Savepoints
For long handlers or handlers that may fail partway through, you can use savepoints to commit work incrementally:
See Using Savepoints for details.
Zero Garbage Programming
For ultra-low-latency applications, you can eliminate garbage collection pauses using zero-garbage techniques:
See Coding for Zero Garbage for details.
See Also
Programming Fundamentals - Core rules for message handlers
Sending Messages - Creating and sending outbound messages
Controlling Transactions - Advanced transaction control
Coding for Zero Garbage - Ultra-low-latency techniques
Event Sourcing Template - Event Sourcing model and requirements
Cluster Consensus - How consensus works (conceptual)
Last updated

