Or: Why things are simple with FIFO

If we chain 2 FIFO queues one after the other, we still get a FIFO queue. This is fairly straightforward to verify, so nothing special.

However, LIFO queues compose in much more interesting (and scary) ways. If we chain 2 LIFO queues, we don't necessarily end up with a LIFO queue. The observed behavior is determined based on the time and rate at which elements are added to or removed from the queues.

For example, let's imagine A and B being 2 actors communicating with each other which A being the sender and B being the receiver. Both have queues on their end for buffering writes and reads respectively. Let's also assume that both Q1 and Q2 are LIFO. A and B might have setup their queues this way to get more recent events across first.

(A —> Q1) —> (Q2 —> B)

If Q1 buffers everything from A and Q2 buffers everything from Q1 before B dequeues elements from Q2, we observe FIFO behavior:

E.g.

Overall behavior is therefore FIFO. Note that this assumes that messages from Q2 to Q1 arrive in the order in which they are sent. This will be true, for example, if Q1 and Q2 are intermediated by a TCP connection. This case is simplistic because we assume that A finishes all writes to Q1 before Q1 forwards to Q2.

In a real life scenario, the sending, forwarding and receiving of these messages might be continuous process. Unfortunately, in that case, it's impossible to predict the sequence of messages arriving at B without a priori knowing the message arrival times, buffering and message delivery times.

E.g.