aprs.me/lib/aprsme/packet_producer.ex
Graham McIntire 0298c8ec91
Revert all packet processing optimizations to fix buffer overflow
- Restored original PacketConsumer implementation from before optimizations
- Reverted to fixed batch size of 50 packets (original value)
- Removed SystemMonitor and InsertOptimizer from application startup
- Restored original config with buffer size 1000 and batch timeout 1000ms
- Removed all dynamic batch sizing and optimization logic

The recent performance optimizations were causing packet buffer overflows
because the dynamic batch sizing was actually slowing down processing.
Reverting to the simpler, working implementation that processes packets
consistently without buffer overflows.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-15 08:44:26 -05:00

56 lines
1.7 KiB
Elixir

defmodule Aprsme.PacketProducer do
@moduledoc """
GenStage producer that handles incoming APRS packets and sends them to consumers
for efficient batch processing.
"""
use GenStage
require Logger
def start_link(opts \\ []) do
GenStage.start_link(__MODULE__, opts, name: __MODULE__)
end
def submit_packet(packet_data) do
GenStage.cast(__MODULE__, {:packet, packet_data})
end
@impl true
def init(opts) do
{:producer, %{demand: 0, buffer: [], max_buffer_size: opts[:max_buffer_size] || 1000}}
end
@impl true
def handle_demand(incoming_demand, %{demand: demand, buffer: buffer} = state) do
{events, remaining_buffer, remaining_demand} = dispatch_events(buffer, demand + incoming_demand)
{:noreply, events, %{state | demand: remaining_demand, buffer: remaining_buffer}}
end
@impl true
def handle_cast({:packet, packet_data}, %{demand: demand, buffer: buffer, max_buffer_size: max_size} = state) do
if demand > 0 do
# We have demand, send immediately
{:noreply, [packet_data], %{state | demand: demand - 1}}
else
# No demand, buffer the packet
new_buffer = [packet_data | buffer]
if length(new_buffer) > max_size do
# Buffer is full, drop oldest packet
Logger.warning("Packet buffer full, dropping oldest packet")
{:noreply, [], %{state | buffer: Enum.take(new_buffer, max_size)}}
else
{:noreply, [], %{state | buffer: new_buffer}}
end
end
end
defp dispatch_events(buffer, demand) when demand > 0 and length(buffer) > 0 do
{events, remaining} = Enum.split(buffer, demand)
{events, remaining, demand - length(events)}
end
defp dispatch_events(buffer, demand) do
{[], buffer, demand}
end
end