Skip to content

Asynchronous Systems

If you're familiar with building systems that use HTTP Request/Response or with similar synchronous interactions, then building your first asynchronous system can be a bit confunding.

The most important difference is that in asynchronous systems, processes run when they run, which is not necessarily when you might expect them to. If you don't understand this, you may get results which seem illogical or incorrect.

Asynchronous System Sample

An example to illustrate the complexity of asynchronous systems is below. The process consists of two Aeron Agents, with bi-directional communication over Aeron IPC. Two scenarios are given - one which leads to a race condition, and one that does not.

async Timer Timer Client Aeron IPC

The core logic in the Timer Client Agent is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
switch (agentState)
{
    ...
    case NORMAL:
        scheduleTimer(normalCorrelation, nowMs + TEN_MILLISECONDS);
        removeTimer(normalCorrelation);
        normalCorrelation += 1;
        break;
    case RACE:
        scheduleTimer(raceCorrelation, nowMs);
        removeTimer(raceCorrelation);
        raceCorrelation += 1;
        break;
    ...
}

The most interesting scenario is the race condition. In both scenarios the scheduleTimer is followed by the removeTimer, with the only difference being that the NORMAL case will schedule the timer 10ms in the future.

The output of a single race condition run is:

13:27:11.071 [timer-client] Scheduling timer with correlation 10000 for deadline 1592155631071
13:27:11.071 [timer-client] Canceling timer with correlation 10000
13:27:11.072 [timer-client] Timer Canceled Event! with correlation 5001
13:27:11.072 [timer] New timer with correlation 5002 for time 1592155631073
13:27:11.079 [timer] Remove timer with correlation 5002
13:27:11.079 [timer-client] Scheduling timer with correlation 10001 for deadline 1592155631079
13:27:11.079 [timer-client] Canceling timer with correlation 10001
13:27:11.079 [timer-client] Timer Canceled Event! with correlation 5002
13:27:11.085 [timer] New timer with correlation 10000 for time 1592155631071
13:27:11.085 [timer] Timer has fired! correlation 10000
13:27:11.088 [timer-client] Scheduling timer with correlation 10002 for deadline 1592155631088
13:27:11.088 [timer-client] Canceling timer with correlation 10002
13:27:11.088 [timer-client] Timer Fired Event! with correlation 10000
13:27:11.091 [timer] Remove timer with correlation 10000
13:27:11.097 [timer-client] Timer Canceled Event! with correlation 10000

Key lines:

  • Line 1: In this case, the timer-client schedules a timer with correlation 10000 for 1592155631071 (which is the current time).
  • Line 2: It follows it up with a cancel request for a timer of the same correlation.
  • Line 9: The timer service receives the New Timer command.
  • Line 10: Since the timer is scheduled to run instantly, the timer service fires the moment the service receives it. - Line 13: The timer-client receives the timer fired event.
  • Line 14: The timer service receives a request to remove the timer with correlation 10000
  • Line 15: The timer-client receives notification that the timer has been removed - a full 12 milliseconds behind the timer being fired, despite scheduling and cancelling the timer at the same time.

Sample source code