Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions ModuleConfig.bx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,15 @@ class {
// Datasource name SQLiteMetricsStore reads/writes, if you opt into it above.
datasourceName = "rulebox_visualizer",
// Max live-tracker (SSE) connections open at once; each pins two server threads. Over the cap, stream() answers 503.
maxStreams = 25
maxStreams = 25,
// SQLiteMetricsStore retention (0 disables either): prune events older than this many days...
retentionDays = 30,
// ...and keep at most this many rows. Checked every ~500 inserts, not on every insert.
maxStoredEvents = 100000,
// SQLiteMetricsStore circuit breaker: after this many consecutive failures stop
// writing for the cool-down (seconds), logging one error on open and one info on recovery.
circuitBreakerThreshold = 5,
circuitBreakerCooldownSeconds = 60
}
}

Expand Down Expand Up @@ -101,7 +109,11 @@ class {
}
// Whole-number settings and the smallest value each accepts
var minimums = {
maxStreams : 1
retentionDays : 0,
maxStoredEvents : 0,
circuitBreakerThreshold : 1,
circuitBreakerCooldownSeconds : 0,
maxStreams : 1
}
for( var key, minimum in minimums ){
var value = arguments.visualizer[ key ] ?: ""
Expand Down
27 changes: 27 additions & 0 deletions docs/guides/visualizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,33 @@ you opt into this store, you set these up yourself. If `bx-sqlite` or the
datasource isn't available, RuleBox logs it and keeps going: live broadcast
still works, nothing gets persisted.

#### Retention, indexing and the circuit breaker

The SQLite store is hardened for long-running apps. All of these settings live
under `visualizer` and are optional:

| Setting | Default | Meaning |
| --- | --- | --- |
| `retentionDays` | `30` | Delete events older than this many days. `0` disables. |
| `maxStoredEvents` | `100000` | Keep at most this many rows (the newest). `0` disables. |
| `circuitBreakerThreshold` | `5` | Consecutive failed writes before the store stops trying. |
| `circuitBreakerCooldownSeconds` | `60` | How long it stays idle before a single trial write. |

- Retention is enforced by a cheap `DELETE` once every 500 inserts, never on
every insert, so the table can briefly exceed the limits between prunes.
- The `rulebox_events` table has an index on `(rulebookName, ruleName, id)` for
the per-rule metrics queries (created automatically; existing tables get it
on the next startup).
- If writes keep failing (a missing datasource, a locked or full database), the
store logs **one** error when the breaker opens, skips persistence for the
cool-down (live broadcast keeps working), then retries once and logs **one**
info line when it recovers. A failed schema create is retried on the next
event rather than being swallowed for good.
- Each recorded event is still a synchronous `INSERT` on the thread that
evaluated the rule. That is a deliberate trade-off for simplicity; if it is
too slow for your traffic, use the in-memory store or implement
`IMetricsStore@rulebox` with a queue.

### Swapping it out

Implement `IMetricsStore@rulebox` (`recordEvent`, `queryEvents`,
Expand Down
2 changes: 1 addition & 1 deletion models/metrics/IMetricsStore.bx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Contract for a Rule Visualizer metrics persistence store. Implement this and point
* moduleSettings.rulebox.visualizer.metricsStore at your WireBox mapping to swap out the
* default SQLiteMetricsStore@rulebox.
* default InMemoryMetricsStore@rulebox (or the opt-in SQLiteMetricsStore@rulebox).
*/
interface {

Expand Down
Loading
Loading