gen_stage
gen_stage copied to clipboard
Fix FIFO ordering for queued sync_info messages
Problem
Addresses #315
The GenStage.Buffer module was returning permanent events in LIFO instead of FIFO order when multiple permanent events were stored at the same wheel position.
Reproduction
alias GenStage.Buffer
# Create a buffer and store some temporary events
buffer = Buffer.new(10)
{buffer, _excess, _perms} = Buffer.store_temporary(buffer, [:temp1, :temp2], :first)
# Store multiple permanent events at the same position
{:ok, buffer} = Buffer.store_permanent_unless_empty(buffer, :perm_first)
{:ok, buffer} = Buffer.store_permanent_unless_empty(buffer, :perm_second)
{:ok, buffer} = Buffer.store_permanent_unless_empty(buffer, :perm_third)
# Take events - notice the permanent events are in wrong order
{:ok, _buffer, _remaining, temps, perms} = Buffer.take_count_or_until_permanent(buffer, 5)
IO.inspect(temps) # [:temp1, :temp2] ✓ Correct FIFO order
IO.inspect(perms) # [:perm_third, :perm_second, :perm_first] ❌ Wrong! Should be FIFO
Before fix: [:perm_third, :perm_second, :perm_first] (LIFO - wrong)
After fix: [:perm_first, :perm_second, :perm_third] (FIFO - correct)
Root Cause
In pop_and_increment_wheel/1, permanent events were stored using [new_perm | existing_list], but when retrieved the list wasn't reversed to restore FIFO order.
Solution
Added :lists.reverse(perms) in pop_and_increment_wheel/1 before returning permanent events, ensuring they're returned in the same order they were stored.