TimescaleDB
What it is
TimescaleDB extends PostgreSQL for time-series and event workloads. Its hypertables automatically partition rows into chunks while remaining queryable as ordinary PostgreSQL tables.
What it provides
- Automatic time-based partitioning through hypertables
- Retention, compression, and tiering policies
- Continuous aggregates and time-series analytical functions
Use it for application metrics, IoT readings, financial ticks, observability events, audit histories, or any append-heavy table primarily queried by time range.
Use it with Rent
extension timescaledb {
name = "timescaledb"
}The RSL declaration makes installation and migration intent part of the reviewed application schema. Register the typed pack at runtime to call its APIs:
let timescale = extensions.register_pack::<TimescaleDb>()?;
let client = timescale.client(&pool);
let metrics = client.hypertable("metrics");
metrics.create("recorded_at").await?;
metrics.retain_for("90 days").await?;
metrics.remove_retention().await?;Retention and compression policies return the 32-bit job ID as an Option<i32>. Removing a retention policy returns ().
Durations are PostgreSQL interval strings, such as "90 days"; invalid intervals return database errors.
Enable compression on the hypertable before calling metrics.compress_after("7 days"). Compression settings
depend on the table's workload and selected TimescaleDB version.
The TimescaleDB profile is tested with its own PostgreSQL image rather than assuming the functions exist in stock PostgreSQL.
Integer time axes
Some event streams use a bigint counter or Unix timestamp instead of a timestamp column. Use ticks consistently: the column, chunk width, retention window, and clock function must all use the same unit.
For a table post_ticks with a bigint tick column, register an existing zero-argument SQL clock that returns
bigint. For example, an epoch-seconds clock can return extract(epoch FROM CURRENT_TIMESTAMP)::bigint.
let events = client.hypertable("public.post_ticks");
events.create_integer("tick", 3_600).await?;
events.integer_clock("public.epoch_seconds").await?;
let retention_job = events.retain_ticks(86_400).await?;Here each chunk spans an hour and the retention window is one day. retain_ticks returns a non-null job ID.
Use retain_for("1 day") for timestamp columns; an interval is not interchangeable with integer ticks.
Missing clocks, mismatched time axes, and duplicate policies return errors. Policy registration uses the bound
transaction, so rolling back also rolls back registration. Background jobs execute separately after commit.
Run the application
cargo run -p rent --example extension_06_timescaledbSet DATABASE_URL to a disposable TimescaleDB server whose role can create databases. The application
creates a post_metrics hypertable, inserts two view-count observations, sums them, and checks that real
chunks exist. It adds and removes retention, enables compression, and verifies the compression job in
TimescaleDB's catalog. Duplicate policies and malformed intervals are checked as errors. The isolated
database is removed afterward.
The same application also creates an integer-time hypertable, registers its clock, checks transaction rollback, and runs its retention job against old and recent chunks. It verifies that only the recent observation remains.
Creating a retention or compression policy registers a background job; it does not immediately delete or
compress your data. Choose intervals for your retention requirements before applying policies in production.
Its standalone extension declaration is crates/rent/examples/extension_06_timescaledb/schema.rsl.