Skip to content

Commit a366a13

Browse files
committed
docs(storage): dedicated DB integration-guide chapters
Split the database backends into their own practical integration-guide chapters, grounded in the implemented config/schema/features: - observability/storage/sqlite.md - observability/storage/postgres.md - observability/storage/timescaledb.md - observability/storage/mongodb.md Each covers: build feature, running the DB (docker), the exact [storage.*] config block and all fields, the auto-created schema/document model, verification (incl. the gated REFLOW_TEST_* integration tests), operations (retention/compression/sharding/backups), and troubleshooting with the real error messages. Nest them under Storage Backends in SUMMARY.md and add an "Integration guides" index to storage-backends.md (now the conceptual overview; the chapters are the walkthroughs).
1 parent 1c8340b commit a366a13

6 files changed

Lines changed: 391 additions & 0 deletions

File tree

docs/SUMMARY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@
5656
- [Data Flow Tracing](observability/data-flow-tracing.md)
5757
- [Configuration](observability/configuration.md)
5858
- [Storage Backends](observability/storage-backends.md)
59+
- [SQLite](observability/storage/sqlite.md)
60+
- [PostgreSQL](observability/storage/postgres.md)
61+
- [TimescaleDB](observability/storage/timescaledb.md)
62+
- [MongoDB](observability/storage/mongodb.md)
5963
- [OTLP Export (Monoscope)](observability/otlp-export.md)
6064
- [Production Deployment](observability/deployment.md)
6165

docs/observability/storage-backends.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ row/document keyed by `trace_id`, with denormalized `flow_id`/`execution_id`/
3232
- **MongoDB Storage** _(available, `--features mongodb`)_: Document store; the JSON-shaped trace maps naturally to a document
3333
- **Custom Storage**: Implement the `TraceStorage` trait yourself
3434

35+
### Integration guides
36+
37+
Step-by-step setup for each database — build feature, run the DB, the exact
38+
config block, the auto-created schema, verification, and operations:
39+
40+
- **[SQLite](storage/sqlite.md)** — embedded, default, zero-ops
41+
- **[PostgreSQL](storage/postgres.md)** — production, multi-instance, high-concurrency
42+
- **[TimescaleDB](storage/timescaledb.md)** — Postgres + time-series hypertable (retention/compression)
43+
- **[MongoDB](storage/mongodb.md)** — document store
44+
45+
This page below is the conceptual overview (model, comparison, selection); the
46+
guides above are the practical walkthroughs.
47+
3548
## Memory Storage
3649

3750
### When to Use
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# MongoDB Integration Guide
2+
3+
MongoDB is a **document-store** backend — the JSON-shaped `FlowTrace` maps
4+
naturally onto a BSON document. A good fit if you already operate MongoDB, want
5+
schema-less retention of the evolving trace shape, or scale horizontally via
6+
sharding.
7+
8+
## Build
9+
10+
Behind a cargo feature (adds the `mongodb` + `bson` drivers):
11+
12+
```bash
13+
cargo build -p reflow_tracing --features mongodb
14+
# or every durable backend at once:
15+
cargo build -p reflow_tracing --features all-backends
16+
```
17+
18+
## Run a database
19+
20+
```bash
21+
docker run -d --name reflow-mongo -p 27017:27017 mongo:7
22+
```
23+
24+
## Configure
25+
26+
Set `storage.backend` to `mongodb` (or `mongo`) and a `[storage.mongodb]` block.
27+
All fields:
28+
29+
```toml
30+
[storage]
31+
backend = "mongodb"
32+
33+
[storage.mongodb]
34+
connection_url = "mongodb://localhost:27017"
35+
database_name = "reflow_tracing"
36+
collection_name = "traces"
37+
```
38+
39+
## Document model
40+
41+
Each `FlowTrace` is one document keyed by its `trace_id` (`_id`), with
42+
denormalized top-level fields for querying and the full trace nested under
43+
`trace`:
44+
45+
```json
46+
{
47+
"_id": "<trace_id>",
48+
"flow_id": "...", "execution_id": "...", "status": "...",
49+
"start_time": 1718000000, "end_time": 1718000005, "event_count": 12,
50+
"trace": { /* the full FlowTrace */ }
51+
}
52+
```
53+
54+
Stores use an upsert (`replace_one … upsert`), and the server creates indexes on
55+
`flow_id`, `execution_id`, `status`, and `start_time` on startup.
56+
57+
## Verify
58+
59+
```bash
60+
reflow_tracing # logs: "Initialized storage backend: mongodb"
61+
62+
mongosh "mongodb://localhost:27017/reflow_tracing" \
63+
--eval 'db.traces.countDocuments()'
64+
mongosh "mongodb://localhost:27017/reflow_tracing" \
65+
--eval 'db.traces.findOne({}, {flow_id:1, status:1, event_count:1})'
66+
```
67+
68+
Live integration test:
69+
70+
```bash
71+
REFLOW_TEST_MONGODB_URL="mongodb://localhost:27017" \
72+
cargo test -p reflow_tracing --features mongodb --test storage_backends \
73+
mongodb_store_query_delete_roundtrip
74+
```
75+
76+
## Operations
77+
78+
- **Retention (TTL)**: a TTL index expires old traces automatically — e.g. add a
79+
BSON `Date` field and
80+
`db.traces.createIndex({ expires_at: 1 }, { expireAfterSeconds: 0 })`, or run a
81+
periodic `deleteMany({ start_time: { $lt: cutoff } })`.
82+
- **Sharding**: shard on `_id` (trace_id) or `flow_id` for horizontal scale.
83+
- **Backups**: `mongodump` / replica sets.
84+
85+
## Troubleshooting
86+
87+
- **`MongoDB backend not compiled in`** — rebuild with `--features mongodb`.
88+
- **`MongoDB storage config missing`**`backend = "mongodb"` but no
89+
`[storage.mongodb]` block.
90+
- **Connection errors** — check `connection_url`, that the server is up, and auth
91+
(`mongodb://user:pass@host:27017`).
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# PostgreSQL Integration Guide
2+
3+
PostgreSQL is the recommended backend for **production, multi-instance, and
4+
high-concurrency** deployments — a real server with connection pooling and strong
5+
durability. For time-series-heavy workloads, see the
6+
[TimescaleDB guide](timescaledb.md), which reuses this same config.
7+
8+
## Build
9+
10+
PostgreSQL is behind a cargo feature (adds the sqlx Postgres driver):
11+
12+
```bash
13+
cargo build -p reflow_tracing --features postgres
14+
# or every durable backend at once:
15+
cargo build -p reflow_tracing --features all-backends
16+
```
17+
18+
## Run a database
19+
20+
```bash
21+
docker run -d --name reflow-pg \
22+
-e POSTGRES_DB=traces -e POSTGRES_USER=reflow -e POSTGRES_PASSWORD=secret \
23+
-p 5432:5432 postgres:16
24+
```
25+
26+
## Configure
27+
28+
Set `storage.backend` to `postgres` (or `postgresql`) and a `[storage.postgres]`
29+
block. All fields:
30+
31+
```toml
32+
[storage]
33+
backend = "postgres"
34+
35+
[storage.postgres]
36+
connection_url = "postgresql://reflow:secret@localhost:5432/traces"
37+
max_connections = 20
38+
min_connections = 5
39+
acquire_timeout_secs = 5
40+
```
41+
42+
## Schema
43+
44+
Created automatically on startup (the `traces` table + indexes) — no manual DDL.
45+
Each `FlowTrace` is one row: the full trace as a (zstd-compressed when large)
46+
JSON `BYTEA` blob, plus denormalized columns:
47+
48+
| column | type | purpose |
49+
|---|---|---|
50+
| `trace_id` (PK) | `TEXT` | identity |
51+
| `flow_id`, `execution_id`, `status` | `TEXT` | query filters |
52+
| `start_time`, `end_time` | `BIGINT` | time-range queries |
53+
| `event_count` | `BIGINT` | stats without loading the blob |
54+
| `data`, `compressed`, `size_bytes` | `BYTEA`/`BOOL`/`BIGINT` | payload |
55+
56+
Stores are **synchronous** with an `INSERT … ON CONFLICT (trace_id) DO UPDATE`
57+
upsert (idempotent re-finalize), and indexes cover `flow_id`, `execution_id`,
58+
`status`, `start_time`.
59+
60+
## Verify
61+
62+
```bash
63+
reflow_tracing # logs: "Initialized storage backend: postgres"
64+
65+
psql "$CONN" -c '\dt' # traces
66+
psql "$CONN" -c 'SELECT count(*) FROM traces;'
67+
```
68+
69+
Run the bundled integration test against a live instance:
70+
71+
```bash
72+
REFLOW_TEST_POSTGRES_URL="postgresql://reflow:secret@localhost:5432/traces" \
73+
cargo test -p reflow_tracing --features postgres --test storage_backends \
74+
postgres_store_query_delete_roundtrip
75+
```
76+
77+
## Operations
78+
79+
- **Pooling**: size `max_connections` to your collector concurrency; `sqlx`
80+
manages the pool with `acquire_timeout_secs`.
81+
- **Retention**: schedule
82+
`DELETE FROM traces WHERE start_time < EXTRACT(EPOCH FROM now() - INTERVAL '30 days')`,
83+
or use [TimescaleDB](timescaledb.md) for native retention.
84+
- **Backups**: standard `pg_dump` / streaming replication / PITR.
85+
- **Scale**: read replicas, partitioning. If your queries are dominated by
86+
time ranges, TimescaleDB's hypertable is a better fit.
87+
88+
## Troubleshooting
89+
90+
- **`PostgreSQL backend not compiled in`** — rebuild with `--features postgres`.
91+
- **`PostgreSQL storage config missing`**`backend = "postgres"` but no
92+
`[storage.postgres]` block.
93+
- **Connection refused / auth failed** — check `connection_url`, that the server
94+
is reachable, and credentials.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# SQLite Integration Guide
2+
3+
SQLite is the **default durable backend** — a single embedded file, no server to
4+
run. Ideal for development, single-node deployments, and anywhere you want
5+
persistence without operating a database.
6+
7+
## Build
8+
9+
SQLite ships in the default build (the `storage` feature is on by default):
10+
11+
```bash
12+
cargo build -p reflow_tracing # SQLite included
13+
```
14+
15+
## Configure
16+
17+
Set `storage.backend = "sqlite"` and a `[storage.sqlite]` block. All fields:
18+
19+
```toml
20+
[storage]
21+
backend = "sqlite"
22+
23+
[storage.sqlite]
24+
database_path = "traces.db" # file path, or ":memory:" for an ephemeral DB
25+
wal_mode = true # Write-Ahead Logging (recommended)
26+
journal_mode = "WAL"
27+
synchronous = "NORMAL" # NORMAL is a good durability/speed balance
28+
cache_size = -2000 # KB when negative (here ~2 MB), pages when positive
29+
```
30+
31+
The database file is **created automatically** if it doesn't exist (the server
32+
opens it with `mode=rwc`); the parent directory must already exist.
33+
34+
## Schema
35+
36+
Created on startup — you never run DDL by hand. Each `FlowTrace` is stored as one
37+
row in `traces`: the full trace is a (zstd-compressed when large) JSON blob in
38+
`data`, alongside denormalized columns for querying:
39+
40+
| column | purpose |
41+
|---|---|
42+
| `trace_id` (PK) | trace identity |
43+
| `flow_id`, `execution_id`, `status` | query filters |
44+
| `start_time`, `end_time` | time-range queries |
45+
| `data` (BLOB), `compressed`, `size_bytes` | the trace payload |
46+
47+
Indexes cover `flow_id`, `execution_id`, `status`, `start_time`. Writes are
48+
**synchronous (write-through)**, so a trace is queryable the instant it's stored.
49+
50+
## Verify
51+
52+
```bash
53+
# point the server at a sqlite config and start it
54+
reflow_tracing # logs: "Initialized storage backend: sqlite"
55+
56+
# after some traces have flowed, inspect the file directly
57+
sqlite3 traces.db '.tables' # traces, trace_events
58+
sqlite3 traces.db 'SELECT count(*) FROM traces;'
59+
```
60+
61+
Or query through the protocol (`get_trace` / `query_traces`) from any SDK / the
62+
monitoring client.
63+
64+
## Operations
65+
66+
- **Backups**: it's a single file — copy it (use the SQLite backup API or copy
67+
while WAL-checkpointed). The WAL (`traces.db-wal`) must travel with the file.
68+
- **Concurrency**: SQLite is single-writer. Fine for one collector; for high
69+
concurrent write volume move to [PostgreSQL](postgres.md) /
70+
[TimescaleDB](timescaledb.md).
71+
- **Retention**: SQLite has no automatic TTL. Prune with
72+
`DELETE FROM traces WHERE start_time < strftime('%s','now','-30 days')` on a
73+
schedule, or use the in-process delete API.
74+
- **Cache**: bump `cache_size` (negative = KB) for read-heavy workloads.
75+
76+
## Troubleshooting
77+
78+
- **`unable to open database file`** — the parent directory doesn't exist, or the
79+
process can't write there. Create the directory / fix permissions.
80+
- **No traces appear** — confirm `backend = "sqlite"` (not `memory`) and that the
81+
network's `TracingConfig.enabled = true` points at this server.
82+
- **`Storage feature is not enabled`** — you built with `--no-default-features`;
83+
re-enable the `storage` feature.

0 commit comments

Comments
 (0)