Current section

Files

Jump to
electric lib electric shape_cache compaction_runner.ex
Raw

lib/electric/shape_cache/compaction_runner.ex

defmodule Electric.ShapeCache.CompactionRunner do
use GenServer
require Logger
alias Electric.ShapeCache.Storage
@schema NimbleOptions.new!(
stack_id: [type: :string, required: true],
shape_handle: [type: :string, required: true],
storage: [type: :mod_arg, required: true],
compaction_period: [type: :non_neg_integer, default: :timer.minutes(10)]
)
def start_link(opts) do
with {:ok, opts} <- NimbleOptions.validate(opts, @schema) do
GenServer.start_link(__MODULE__, opts, name: name(opts))
end
end
def name(opts) do
Electric.ProcessRegistry.name(opts[:stack_id], __MODULE__, opts[:shape_handle])
end
@impl GenServer
def init(opts) do
clean_after_period(opts)
Process.set_label({:compaction_runner, opts[:stack_id], opts[:shape_handle]})
Logger.metadata(stack_id: opts[:stack_id], shape_handle: opts[:shape_handle])
{:ok, opts}
end
@impl GenServer
def handle_info(:clean, opts) do
Logger.info("Triggering compaction for shape #{opts[:shape_handle]}")
clean_after_period(opts)
Storage.compact(opts[:storage])
Logger.info("Compaction complete for shape #{opts[:shape_handle]}")
{:noreply, opts}
end
defp clean_after_period(opts) do
# add a large random jitter to avoid all compactions happening at the same time
half_period = div(opts[:compaction_period], 2)
next_msg = opts[:compaction_period] + Enum.random(-half_period..half_period)
Process.send_after(self(), :clean, next_msg)
end
end