Packages

An Elixir library for real-time state sync and delta tracking, with ETS, Redis, and periodic cleanup support.

Current section

Files

Jump to
chord lib chord cleanup server.ex
Raw

lib/chord/cleanup/server.ex

defmodule Chord.Cleanup.Server do
@moduledoc """
Periodic cleanup server for stale contexts and deltas.
This server periodically triggers the cleanup logic defined in `Chord.Cleanup`,
removing stale entries from the backend.
## State
The server's state includes:
- `:interval` - The interval (in milliseconds) between cleanup executions.
- `:backend_opts` - A keyword list of options passed to backend listing functions.
## Example
Chord.Cleanup.Server.start_link(interval: :timer.minutes(30), backend_opts: [limit: 100])
"""
use GenServer
require Logger
alias Chord.Cleanup
@default_interval :timer.hours(1)
@doc """
Starts the cleanup server with the specified options.
## Options
- `:interval` (integer): Time interval in milliseconds for periodic cleanup (default: 1 hour).
- `:backend_opts` (Keyword.t): Options passed to backend listing functions (see "Common Options" in the `Chord` module).
## Example
iex> Chord.Cleanup.Server.start_link(interval: :timer.minutes(30), backend_opts: [limit: 50])
{:ok, pid}
"""
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, name: Keyword.get(opts, :name, __MODULE__))
end
@doc """
Updates the interval for periodic cleanup at runtime.
## Parameters
- `new_interval` (integer): The new interval in milliseconds.
- `name` (atom): The name of the `GenServer` instance. Defaults to `__MODULE__`.
## Returns
- `:ok` if the interval was successfully updated.
"""
def update_interval(new_interval, name \\ __MODULE__) do
GenServer.call(name, {:update_interval, new_interval})
end
@doc """
Updates the backend options for periodic cleanup at runtime.
## Parameters
- `new_opts` (Keyword.t): The new backend options.
- `name` (atom): The name of the `GenServer` instance. Defaults to `__MODULE__`.
## Returns
- `:ok` if the backend options were successfully updated.
"""
def update_backend_opts(new_opts, name \\ __MODULE__) do
GenServer.call(name, {:update_backend_opts, new_opts})
end
@impl true
def init(opts) do
interval = Keyword.get(opts, :interval, @default_interval)
backend_opts = Keyword.get(opts, :backend_opts, [])
Logger.info(
"Cleanup server started with interval: #{interval} ms and options: #{inspect(opts)}"
)
schedule_cleanup(interval)
{:ok, %{interval: interval, backend_opts: backend_opts}}
end
@impl true
def handle_call({:update_interval, new_interval}, _from, state) do
Logger.info("Updating cleanup interval from #{state.interval} ms to #{new_interval} ms")
{:reply, :ok, %{state | interval: new_interval}}
end
@impl true
def handle_call({:update_backend_opts, new_opts}, _from, state) do
Logger.info(
"Updating backend options from #{inspect(state.backend_opts)} to #{inspect(new_opts)}"
)
{:reply, :ok, %{state | backend_opts: new_opts}}
end
@impl true
def handle_info(:cleanup, state) do
opts = state.backend_opts
Logger.info("Starting cleanup operation with state: #{inspect(state)}")
Cleanup.periodic_cleanup(opts)
schedule_cleanup(state.interval)
{:noreply, state}
end
def handle_info(_unknown_message, state) do
Logger.warning("Received unknown message in cleanup server")
{:noreply, state}
end
@doc false
defp schedule_cleanup(interval) do
Logger.debug("Scheduling next cleanup operation in #{interval} ms")
Process.send_after(self(), :cleanup, interval)
end
end