Skip to content

Agent Concurrency Model

Michael Barker edited this page Aug 26, 2021 · 1 revision

(Not to be confused with the Agrona Agent logging)

Agrona provides a mechanism for encapsulating units of work and running them in using an arbitrary threading setup. The key interface is the Agent, which is similar in a few ways to Java's Runnable interface in that there are various ways that a Runnable can be executed (e.g. as a Thread, submitted to a thread pool, etc). However, there is an important distinction. The key execution method of the Agent interface is the doWork method. The purpose of this method is not to run indefinitely, but do a bounded amount of work then return and indicate how much work has been done. E.g. the number of messages processed. The purpose of have a unit which does a small amount of work then returns is so that multiple instances of these can be run together on the same thread if required. This is very similar to a co-operative multi-tasking system. Building a system out of a number of agents in the manner allows for a lot of flexibility with regards to thread and CPU usage. Most commonly the Aeron Media Driver bus uses agents for each of its core execution units (reciever, sender, conductor), having each implemented as agents means that the Media Driver can run all three in one thread, spread them across separate threads, or even not run them at all, but give the caller an interface to call to run the Media Driver's agents itself.

There are some key constraints to the implementation of an Agent that the user should be aware of. Mostly that the work should be bounded and should not block for any extended length of time. Doing so could mean that other Agent instances would get starved of resources.

Running Agents

The main class used to run agents is the AgentRunner which allows one or more agents to be run together under a single Runnable interface.
This is the glue between the Agrona concurrency model and Java's.
The AgentRunner can then be launched in a thread or submitted to a thread pool or whichever model the user likes to take.

IdleStrategies and the doWork Method

Because the Agent model is poll based, we need to have a way for the system to back off its use of the CPU, especially when there is no work to do. This is the reason why the doWork method returns an integer value. If no work is done, then it will return 0, which means that the IdleStrategy can decide to back off from the CPU in whichever way it prefers (yield, sleep, spin...).

Communication Between Agents

Agents are not prescriptive with regards to how they send messages between each other. This can be handled in whatever manner is most useful for the caller (queues, ring buffers, networking) as long as the Agent itself does not block.