Programming Fundamentals
Overview
The Talon programming model is quite straightforward: all business logic in a Talon application is performed by event handlers that are invoked by Talon in response to received messages. The event handlers update state and generate outbound messages to interact with the outside world as a result of the business logic processing. Before diving into more details, this section describes the high level rules that developers must obey when working with Talon.
Messaging
Talon's messaging APIs are discussed in more depth in sections on Configuring Messaging and Authoring User Code later in this manual. In the meantime keep the following rules in mind.
Inbound Messages
An application may not modify inbound messages. Aside from being good practice, the platform relies on this immutability to do background journalling and replication of the message in parallel with your message handlers.
Outbound Messages
Once an application sends an outbound message, it must not attempt to modify or reuse the message. This implies that any particular message instance can only be sent once. Applications may copy a message that has been sent and send it elsewhere. The reason for this is that the platform may concurrently serialize the message for replication or persistence purposes in parallel with your application logic.
Messages Scoped to Handlers
In general, it is bad practice to hold onto a message or its embedded entity fields beyond the scope of a message handler. This is because the platform pools these messages and their underlying contents can be reset after return from a handler. This means that if applications intend to hold onto a message or a portion of the message in the microservice store, the safest approach is to copy them (or their contents) into the store.
In advanced use cases where an application must hold onto a message or one of its embedded entities for a short period of time, copy can be avoided by acquiring a reference to the message via a call to its acquire() method. If the application does acquire() the message it should later dispose() of the message to allow the platform to reuse it.
See Coding for Zero Garbage for more information.
Forwarding Messages
Inbound messages may not be resent as outbound messages. Applications that need to forward an inbound message as an outbound message should first copy() the message and send the message copy:
Threading
Single Threaded State
Microservice models espouse a model where the store is private to each microservice. One of the primary motivators behind this model is that it avoids scalability bottlenecks that can arise from multiple processes contending to update the store. Talon microservices take this concept even further by making the microservice store private to a single processing thread. This restriction is key to Talon's ability to perform and scale by avoiding thread contention and best utilizing processors' CPU caches.
This means:
Applications should be designed to scale horizontally by partitioning state.
No Blocking In Handlers
Talon microservices are optimized for stream-oriented message processing. This means that message handlers should never perform blocking operations. Additionally, since Talon applications have a single-threaded state model, Talon is not optimized for long running, compute intensive operations.
In practice this is generally not an issue for the class of applications targeted by Talon.
Talon handles I/O operations for applications, so applications should not be working with blocking I/O resources.
If an application needs to make a blocking callout to interact with a remote resource, that interaction should be done asynchronously via messaging.
For compute intensive tasks triggered by processing a message, applications may schedule the work on another thread and inject the results back into the engine to update the microservice store.
State Tree Limitations
There are several restrictions enforced by Talon's state model that application developers must be aware of when designing state models and authoring applications. Understanding these limitations is critical for building correct applications.
Single Parent Restriction
An entity may only be placed in the state tree as the field of a single parent object. Using the same object instance in the tree in multiple locations is not supported.
Attempting to set an entity as a field of another entity when it is already set as a field elsewhere in the state tree will result in an IllegalStateException at runtime.
Workaround: Store entities in a Map and reference them by ID. For example, if a Customer object needs to be referenced in multiple places in the state tree, hold all Customers in a Map and reference each Customer by its ID from multiple locations.
Multiple Entity Fields of Same Type
Transactional entities don't currently support multiple fields of the same entity type. The following model is not supported due to limitations in the underlying transaction machinery:
This will yield an error during code generation:
State Tree Cycles
As a corollary to the Single Parent Restriction, cycles in the state tree are not supported (including self-references):
Primitive Collections
It is not currently possible to define collections with primitive value types. Use boxed types (e.g., Integer instead of int) for collection elements.
Inheritance and Polymorphism
Inheritance is not currently supported in Talon's state model. However, the platform supports entity inlining to provide a form of polymorphism:
Application developers should be aware that polymorphism can have a significant impact on Java performance.
Event Sourcing Considerations
Of Talon's two High Availability models (State Replication and Event Sourcing), the more advanced is Event Sourcing. The Event Sourcing model is best suited to applications that require very low latency, but it does impose some additional programming restrictions.
An application using Event Sourcing must be able to exactly reconstruct the same state and outbound messaging stream by replaying the same sequence of inbound events. This implies that business logic that updates state must not rely on any environmental state when making updates to its recoverable state or outbound messages. For example, setting the system time in an outbound message would not produce the same outbound message when the event stream is replayed at a later date or on a different system.
See Event Sourcing Template for more information on working with Event Sourcing and considerations for environment replication.
Last updated

