aprs.me/lib/aprsme/workers/packet_cleanup_worker.ex
Graham McIntire b08eba2c6b
Partition packets table by day and simplify cleanup
Convert the packets table to a time-partitioned table with daily
partitions (PARTITION BY RANGE on received_at). This replaces the
expensive CTE-based batch DELETE cleanup with instant DROP TABLE
partition drops — no dead tuples, no WAL pressure, no VACUUM needed.

- Add PartitionManager GenServer to create/drop daily partitions
- Simplify PacketCleanupWorker to delegate to PartitionManager
- Replace gridsquare/geocalc deps with local Maidenhead module
- Remove gettext_pseudolocalize dependency
- Fix Decimal comparison in packet consumer test
2026-02-20 11:25:16 -06:00

67 lines
2.1 KiB
Elixir

defmodule Aprsme.Workers.PacketCleanupWorker do
@moduledoc """
Worker for cleaning up old APRS packet data.
Delegates to `PartitionManager.drop_old_partitions/1` which drops entire
daily partitions past the retention period — instant, no dead tuples, no VACUUM.
Also cleans up old `bad_packets` records via standard DELETE.
"""
import Ecto.Query
alias Aprsme.BadPacket
alias Aprsme.PartitionManager
alias Aprsme.Repo
require Logger
@spec perform(map()) :: :ok | {:error, String.t()}
def perform(%{"cleanup_days" => days}) when is_integer(days) and days > 0 do
Logger.info("Starting scheduled APRS packet cleanup for packets older than #{days} days")
{:ok, dropped} = PartitionManager.drop_old_partitions(days)
Logger.info("APRS packet cleanup complete: dropped #{length(dropped)} partition(s) older than #{days} days")
:ok
rescue
error ->
Logger.error("Packet cleanup failed: #{inspect(error)}\n#{inspect(__STACKTRACE__)}")
{:error, "Cleanup failed: #{inspect(error)}"}
end
@spec perform(map()) :: :ok | {:error, String.t()}
def perform(_args) do
Logger.info("Starting scheduled APRS packet cleanup")
retention_days = Application.get_env(:aprsme, :packet_retention_days, 7)
{:ok, dropped} = PartitionManager.drop_old_partitions(retention_days)
bad_packet_count = cleanup_old_bad_packets()
Logger.info(
"APRS packet cleanup complete: dropped #{length(dropped)} partition(s) and removed #{bad_packet_count} bad packets older than #{retention_days} days"
)
:ok
rescue
error ->
Logger.error("Packet cleanup failed: #{inspect(error)}\n#{inspect(__STACKTRACE__)}")
{:error, "Cleanup failed: #{inspect(error)}"}
end
defp cleanup_old_bad_packets do
retention_days = Application.get_env(:aprsme, :packet_retention_days, 7)
cutoff_time = DateTime.add(DateTime.utc_now(), -retention_days * 86_400, :second)
{deleted_count, _} =
Repo.delete_all(from(b in BadPacket, where: b.attempted_at < ^cutoff_time))
deleted_count
rescue
error ->
Logger.error("Failed to clean up bad packets: #{inspect(error)}")
0
end
end