The Turbo-Mailbox

A more flexible way to build enterprise applications

Dick Dowdell
Nerd For Tech
9 min readMay 12, 2024

--

How you organize the components of an application system — and how you connect them— are important decisions. In most cases, those choices are too time consuming and expensive to change once you have started to build an application. There’s a better way ...

A better approach involves leveraging flexible architectural principles from the outset — by incorporating modularity and scalability in your design — to more easily accommodate future changes with minimum cost and disruption.

By architecting enterprise systems that can evolve by using modular components and turbo-mailboxes, developers can respond more economically to changing needs and opportunities.

Just how do we do that? We first have to make some important choices. What do we want from our components and how do we need to connect them?

Component Models

Using the right software component models can offer significant advantages for the development, maintenance, and scalability of enterprise software applications and enterprise data.

These benefits are central to many modern software engineering practices, in order to enhance efficiency, reliability, and adaptability. It is important that these software components:

Are Discoverable

Components should be discoverable by the middleware that delivers requests and events. They should be accessible anywhere on the network.

Discoverability assists in the implementation of self-configuration, failover, and load balancing.

Are Stateless and Reentrant

Components should be stateless and capable of processing a single request or event with a single thread, optimizing their efficiency.

They must be fully reentrant so that they can process multiple requests or events concurrently.

Are Reactive

Components should react to incoming requests or events by executing logic, making requests, or publishing events. They may also read from and write to persistent storage if they represent persistent entities.

Reactive components emphasize responsiveness, scalability, resilience, and message-driven communication.

Implement a Domain-Bounded Context

Individual components should have a clear application domain scope and focus on a specific functional or business capability.

Well-defined domain scope enhances independent deployability and honors application ownership and responsibility boundaries.

Use Self-Contained Requests and Events

All the information required by the component to process a request or event message should be present in the incoming message itself or in a persistent data store.

Request and event messages should be self-describing and not require the added complexity of a separate schema management system.

Self-contained requests and events better support autonomy, loose coupling, and version management.

Use a Single Class for Entity Access

Access to persistent data entities should be through a single class dedicated to that specific entity class.

A single class per data entity enhances code organization, reusability, maintainability, and testability.

Overall, this component-based approach aligns well with principles of good software engineering such as encapsulation, abstraction, and separation of concerns. These principles help manage complexity and enable more systematic and predictable software evolution.

What Are Our Connection Choices?

When connecting software components within a system, we have many methods to choose from, each offering different benefits and trade-offs in terms of complexity, scalability, performance, and maintainability.

Modern applications typically operate over networks, which narrows the feasible connectivity options to remote procedure calls (RPCs) and messaging.

Messaging

This approach involves sending and receiving messages through middleware that can manage messages until they are processed. Messaging can support both synchronous and asynchronous communication as well as queued events, so it inherently supports loose coupling. This allows services to be more independent and resilient, enhancing system flexibility.

RPCs

RPCs act like local function calls but over a network. The client sends a request and waits for the server to process the request and return a response. This method is conceptually synchronous and involves tighter coupling between client and server, which can lead to challenges in scalability and fault tolerance.

Both messaging and RPCs use middleware to facilitate communication between components. However, messaging generally allows for more dynamic scaling based on load and is more fault-tolerant, as it can retry or reroute messages without impacting the sender. It’s particularly suited for distributed systems where components might be spread across different physical locations and require reliable, decoupled, and fault-tolerant processing.

In contrast, RPCs are better suited for environments where immediate, synchronous interactions are necessary. Although simpler in concept due to their resemblance to traditional function calls, they can complicate error handling and increase sensitivity to service outages, and are inherently more tightly coupled.

Ultimately, the choice between messaging and RPCs depends on specific application requirements, including response time needs and network reliability. Messaging infrastructures, with their flexibility and self-organizing capabilities, often provide more power and adaptability compared to RPC-based systems.

What Is a Turbo-Mailbox?

A mailbox is a concept used in distributed systems to manage messages when communicating between components. A turbo-mailbox functions as an intermediary to route messages to intended recipients and to manage the compromises among consistency, availability and partition tolerance identified by the CAP Theorem. This method effectively decouples the sending and receiving activities, enabling them to function reasonably independently.

The CAP Theorem

Common Uses of Mailboxes

  • Actor Model: Each actor in this model possesses a mailbox. Actors communicate by sending messages to one another’s mailboxes, processing messages sequentially to ensure controlled and predictable state changes.
  • Composable Services: Individual services can send and receive messages — and publish and subscribe to events — through turbo-mailboxes.
  • Message Queues: Widely used in enterprise settings, message queues implement the mailbox concept to facilitate communication across different system parts, enhancing load balancing and fault tolerance.
  • Event-driven Architectures: In these systems, mailboxes queue events triggered by actions such as user inputs or sensor readings, organizing them by priority or sequence for processing.

Turbocharging a mailbox in the context of distributed systems refers to enhancing its capabilities, performance, efficiency, and reliability.

While conventional mailboxes have a one-to-one relationship with the individual components they service — turbocharged mailboxes have the following enhanced capabilities that regular mailboxes do not have:

Communication Patterns

Turbo-mailboxes facilitate multiple communication patterns, ranging from simple synchronous request-response messaging, through asynchronous messaging to a specific component class, to more complex arrangements like publishing events for interested subscribers.

This versatility allows developers to choose one or more different communication patterns to best support their application’s varied requirements — like using a combination of service-oriented and event-driven processing — depending upon specific use cases.

Turbo-Mailbox Communication Patterns

Purpose and Functionality

In a distributed system, turbo-mailboxes act as an intermediary between message senders and receivers. This architecture permits a turbo-mailbox to deliver a message to any available instance of the target component — facilitating failover, performance tuning, and load balancing.

Message Handling and Queuing

Messages sent through a turbo-mailbox will be dispatched differently depending upon the verb used:

  1. SEND a message to the specified component class is synchronous — returning a response from the receiving instance of the class.
  2. POST a message to the specified component class is asynchronous — with receipt by the mailbox confirmed to the POSTer before the message is forwarded to the receiving instance. If necessary, subsequent error handling is the responsibility of the turbo-mailbox.
  3. PUBLISH an event to a topic queue is asynchronous — through a topic queue to all its subscribing component instances. If necessary, subsequent error handling is the responsibility of the turbo-mailbox.

Queued messages can guarantee “Once and Only Once Delivery” which ensures that an event message is delivered exactly one time to each of its subscribers, neither losing the message nor delivering it multiple times. If an event message cannot be delivered, it is sent to a dead-letter queue for logging and error resolution.

Synchronization and Concurrency

Turbo-mailboxes contribute to synchronization control in distributed settings by offering a systematic way to manage incoming data, reducing concerns like concurrency issues by serializing access to shared resources.

Fault Tolerance and Reliability

To improve fault tolerance, turbo-mailboxes may be designed with features like message retry to other available nodes or persistence in durable storage to avoid data loss during component failures. Techniques such as dead-letter queues help manage messages that fail to process.

Scalability

Turbo-mailboxes support scalability in distributed systems by enabling the addition of more nodes or components without changes to the underlying communication infrastructure. Load balancing strategies can distribute workload evenly across multiple turbo-mailboxes to avoid overloading any single component type.

Optimize Message Handling Policies

Implement advanced message queueing policies such as priority queueing where critical messages are processed first. This ensures that important tasks are completed in a timely manner, improving the system’s responsiveness.

Increase Concurrency

Enhance the system’s ability to handle concurrent message processing. Turbo-mailboxes do this by allowing multiple messages to be processed simultaneously, utilizing multi-threading or asynchronous processing techniques to improve throughput.

Scalable Infrastructure

Use a scalable messaging infrastructure that can dynamically adjust resources based on the load. This can include demand-based services that can automatically scale up to accommodate high traffic and scale down during quieter periods to optimize costs.

Load Balancing

Distribute incoming messages across multiple turbo-mailboxes or servers to prevent any single point of overload. Implementing a load balancer can help evenly distribute traffic and improve system reliability and speed.

Reliability Enhancements

Implement fault tolerance features such as message replication and persistence. Ensuring that messages are stored in a durable manner and replicated across multiple nodes can prevent data loss and allow for recovery in case of system failures.

Advanced Monitoring and Management Tools

Deploy comprehensive monitoring and management tools to provide real-time insights into the mailbox performance. This helps in identifying bottlenecks, predicting potential issues, and facilitating proactive management of the system.

Optimized Data Serialization

Streamline data serialization and deserialization processes. Using efficient serialization formats or protocols can reduce the overhead and speed up the transmission and processing of messages.

Message Compression

Implement compression techniques to reduce the size of messages transmitted between components. This can lead to faster transmission times, lower bandwidth usage, and improved overall performance of the system.

Dead Letter Handling

Develop robust mechanisms to handle undeliverable messages, such as dead-letter queues. This helps in managing message failures and ensures that issues are logged and addressed without affecting the system’s continuous operation.

By applying these enhancements, you can significantly “turbocharge” the performance of a mailbox in a distributed system, ensuring that it can handle high loads, remain reliable under stress, and efficiently process messages.

The Turbo-Mailbox’s Superpower

The turbo-mailbox has a superpower. It can act as a message orchestrator for multiple discoverable components. When a discoverable component is placed in the component directory of a turbo-mailbox instance, it is automatically detected by that turbo-mailbox. The discoverable component is then queried by the turbo-mailbox, and gives the turbo-mailbox all the information necessary to communicate with it.

If the discoverable component subscribes to an event topic, the turbo-mailbox subscribes to that topic queue and polls it on behalf of the component. Incoming events are sent to the subscribing service.

Turbo-mailboxes are federated. That means that turbo-mailboxes on a network share information with each other about the discoverable components they service and can deliver messages to any discoverable component on that network.

A turbo-mailbox can intelligently route messages synchronously to a single recipient as a request with an expected response — post messages asynchronously to a single recipient expecting only receipt confirmation from the turbo-mailbox — or asynchronously to subscribers as an event.

Message Passing Across Federated Turbo-Mailboxes

A message can be delivered over a network — but is delivered as a local call if both the sender and receiver are serviced by the same turbo-mailbox.

Federated Messaging

Overall, turbo-mailboxes are a powerful concept for building robust, scalable, and flexible distributed systems, ensuring effective communication and coordination across various components.

If you are interested in learning more about how, there’s some suggested reading below. If you would like to dive further into the details of turbo-mailboxes please leave a comment or send a Medium private message. We’d love to talk to you.

If you found this article useful, a clap would let us know that we’re on the right track.

Thanks!

Suggested Reading:

In the articles below, the term composable service is interchangeable with discoverable service and the term message orchestrator is interchangeable with turbo-mailbox. We are still trying to identify terminology that is meaningful and descriptive to people.

--

--

Dick Dowdell
Nerd For Tech

A former US Army officer with a wonderful wife and family, I’m a software architect and engineer who has been building software systems for 50 years.