Pixelex.Partitions (Pixelex v0.1.0)

Copy Markdown View Source

Monthly partitions for pixelex_events: create them ahead of time, drop them when they age out.

Why this has to be scheduled

A range-partitioned table with no partition covering now() rejects every insert. Nothing degrades gracefully — ingestion simply stops at midnight on the first of the month. So ensure/1 runs ahead, and it must keep running:

# with Oban
config :my_app, Oban,
  plugins: [{Oban.Plugins.Cron, crontab: [{"0 3 * * *", Pixelex.Partitions.Worker}]}]

ensure/1 is idempotent, so running it hourly is fine and running it on boot is a reasonable belt-and-braces.

Retention

drop_expired/1 drops whole partitions whose entire range is older than the cutoff. DELETE FROM pixelex_events WHERE occurred_at < … would do the same thing by rewriting the largest table in the system and leaving the space to vacuum; DROP TABLE on a partition returns it to the filesystem immediately.

The cost is granularity: a partition survives until its newest row is expired, so with 90-day retention rows live 90–120 days. That is the trade monthly partitions make. Weekly partitions tighten it at the cost of more relations; set :partition_period to :week if the policy needs it.

Summary

Functions

Drop every partition whose whole range predates retention_days ago.

Create partitions covering this month and ahead further months.

Partition names with the exclusive upper bound of each range.

Functions

drop_expired(retention_days \\ nil)

@spec drop_expired(pos_integer() | nil) :: [String.t()]

Drop every partition whose whole range predates retention_days ago.

Returns the names dropped.

ensure(ahead \\ 2)

@spec ensure(non_neg_integer()) :: :ok

Create partitions covering this month and ahead further months.

Idempotent — CREATE TABLE IF NOT EXISTS.

existing_partitions()

@spec existing_partitions() :: [{String.t(), Date.t()}]

Partition names with the exclusive upper bound of each range.