Interface Message
- All Known Implementing Classes:
DefaultMessage
Overview
Messages are used between Actors and therefore are typically declared as independent top-level classes. Most Messages in Sodacan are just containers for some important capabilities:
- MessageId - can be thought of as a transaction Id. It can group together any number of steps in a business process. And the messageId is also used as a correlation Id during parallel fan-out fan-in processing.
- Routing stack - where the message is headed. The top-of-stack refers to the next Actor that the message is routed to.
- Current route - If the message is currently being processed by an Actor, this primarily contains the Verb (the ask) for what it should do,
- Routing History - When a route is popped off of the routing stack, it is added to the routing history.
- Payload - The payload carries any number of primitive or complex data organized as key-value pairs. As a message travels from actor-to-actor, the payload can accumulate data relevant to the transaction.
A Message object is what the Actor programmer normally sees. However, when a Message is in transit, it is called a Jug which consists of the serialized content of the message with the ActorId of the immediate destination of the message in plain-text.
Message Lifecycle
A message has a specific beginning and ending. A message travels from Actor to Actor. A message is created by the configuration object by some Actor. Normally, the message exists until it explicitly "consumed". Messages can also be "held" by an actor although this should only occur in specific cases. While a message is traveling between actors, most of its contents are serialized into a Jug making it hard to analyze. This usually isn't an issue because Actors always see messages in their deserialized form.
Note: All of the following occurs in the Actor's thread. While Sodacan processes a message, it ensures that the message makes it back out the other side of the Actor's processMessage method. Technically, the message itself is immutable but the contents of the message are used to create one or more messages. So, if message A is being processed, then Message A should appear among the messages in the "Stage". Any other Messages in the Stage will have been created by the Actor.
Now, to complicate matters, a Message can be "split". This means that a Message inbound to an actor can be cloned into more than one output messages. The rule above still applies, only there is more than one copy of the message in the Stage. Each of the clones will have the same MessageId. This is done to allow a single "business flow" to operate in parallel for one or more steps in its lifecycle. Split messages can and likely will travel to different Hosts. A split like this normally forward the initial message and forwarding it to the Actor that will collect the results and of course zero or more clones that will end up at the same collecting Actor. Usually, the clones will end their lifecycle in the collecting Actor. Once the collecting Actor receives the expected number of results from each clone, it can forward on the original message to the next step(s).
A message is officially done when it is placed on the stage with an empty Routing Queue, ie there is no more Steps in the process.
Observability
Because a message has a unique id, it can be tracked although this is usually not the case in production.
Messages provide a natural transport for certain trace requirements. A Sodacan message represents a business transaction typically carrying with is much of the data associated with that transaction. It carries with it the Actors that it will visit and the Actors that it has visited.
During its lifetime a message can travel to many Actors.
When a message is created it can start with an ActorId already in its routing stack. That Actor can collect some or all Messages for analysis. For example, the default messageId generator in part uses a UTC Instant. If the final route in a messages life is to an actor that measures the total elapsed time of a message.
Another approach is to Subclass the DefaultMessage class in which case the subclass can do fine-grained tracing to any mechanism desired. In this case, a message can keep track of each step in its journey incling the elapsed time used in each step. Also, Sodacan calls additional method stub in a Message allowing further traceability.
-
Method Summary
Modifier and TypeMethodDescriptioncopyRoutesFrom
(Message inbound) Find the info with the matching name (case insensitive).<T> T
getActorId
(String key) Find the Info record the matching name (case insensitive) and return its String ContentsReturn a copy of the message routing historyint
getInteger
(String key) Find the integer Info matching the name (case insensitive) and return its Integer ContentsReturn a copy of the payloadgetRoute()
Get the current route.Find the Info record the matching name (case insensitive) and return its String ContentsGet the target actorId of the current route.getVerb()
Get the verb of the current route.boolean
keepHistory
(boolean keepHistory) notImplemented
(Config config, Actor actor) This method is called when a message is sent to an Actor but the Actor has not overriden the processMessage method.popRoute()
boolean
postprocess
(Config config, Actor actor) This method is called when a message is sent by an Actor.boolean
preprocess
(Config config, Actor actor) This method is called after a message is deserialized and ready to be processed by the target actor.void
print
(PrintStream out) Put new entry in payloadPut new entry in payload convenience for a StringPut new entry in payload convenience for an ActorIdRemove entry from payloadvoid
This method is called when a message is sent by an Actor and the message as no further routes this it will be destroyed just after this method is called.
-
Method Details
-
getMessageId
MessageId getMessageId() -
getTimestamp
Instant getTimestamp() -
getNextActorId
ActorId getNextActorId() -
getNextVerb
Verb getNextVerb() -
getHistory
Return a copy of the message routing history- Returns:
-
keepHistory
-
isKeepHistory
boolean isKeepHistory() -
getRoute
Route getRoute()Get the current route. This is the route that gave rise to this call to processMessage- Returns:
- The current route
-
getTarget
ActorId getTarget()Get the target actorId of the current route. This is the route that gave rise to this call to processMessage- Returns:
- The current target actorId
-
getVerb
Verb getVerb()Get the verb of the current route. This is the route that gave rise to this call to processMessage- Returns:
- The current verb
-
getRoutes
-
peekRoute
Route peekRoute() -
popRoute
Route popRoute() -
print
-
copyRoutesFrom
-
from
-
ask
-
ask
-
to
-
preprocess
This method is called after a message is deserialized and ready to be processed by the target actor. The default implementation does nothing. This method can be overridden in a Message subclass to provide fine-grained tracing or additional message validation.This method executes in the Actor's thread.
- Parameters:
config
-actor
- The Actor that is about to process this message- Returns:
- true if the message should be processed
-
postprocess
This method is called when a message is sent by an Actor. This happens just before the message is serialized for transport to its current destination. A subclass of a default message can use this method to evaluate the message as well as the Actor that created or forwarded the message. This method can be overridden in a Message subclass to provide fine-grained tracing.This method executes in the Actor's thread.
- Parameters:
config
-actor
- The Actor that just processed this message- Returns:
- true if the message should be processed
-
notImplemented
This method is called when a message is sent to an Actor but the Actor has not overriden the processMessage method. The default behavior is to return an empty Stage. An alternate would be to put the inbound message back into the Stage (it will be sent to the next item in the Route stack, if any). A subclass of a default message can use this method to provide alternate behavior or to forwarded the message.This method executes in the Actor's thread.
- Parameters:
config
-actor
- The Actor that received (but didn't process) this message- Returns:
- The Stage to be processed
-
terminal
This method is called when a message is sent by an Actor and the message as no further routes this it will be destroyed just after this method is called. A subclass of a default message can use this method to evaluate the message as well as the Actor that created or forwarded the message to ensure that its demise is justified.This method executes in the Actor's thread.
- Parameters:
config
-actor
- The Actor that just processed this message
-
getPayload
Return a copy of the payload- Returns:
- A new payload object
-
put
Put new entry in payload- Parameters:
value
- The Payload value- Returns:
- Message builder-style
-
put
Put new entry in payload convenience for a String- Parameters:
key
- A string identifying the payload entryvalue
- The Payload value- Returns:
- Message builder-style
-
put
-
put
Put new entry in payload convenience for an ActorId- Parameters:
key
- A string identifying the payload entryvalue
- The ActorId to add- Returns:
- Message builder-style
-
get
Find the info with the matching name (case insensitive).- Parameters:
key
-- Returns:
-
get
-
getString
Find the Info record the matching name (case insensitive) and return its String Contents- Parameters:
key
-- Returns:
-
getActorId
Find the Info record the matching name (case insensitive) and return its String Contents- Parameters:
key
-- Returns:
-
getInteger
Find the integer Info matching the name (case insensitive) and return its Integer Contents- Parameters:
key
-- Returns:
-
remove
Remove entry from payload- Parameters:
key
- The key to remove- Returns:
- the message object
-