Skip to content

feat(options): Add runtime options for killswitches#421

Draft
jan-auer wants to merge 5 commits intomainfrom
feat/objectstore-options
Draft

feat(options): Add runtime options for killswitches#421
jan-auer wants to merge 5 commits intomainfrom
feat/objectstore-options

Conversation

@jan-auer
Copy link
Copy Markdown
Member

@jan-auer jan-auer commented Apr 7, 2026

sentry-options delivers runtime configuration as untyped JSON blobs. Using it directly means matching option names at every callsite, cloning values out of the snapshot, and accepting that deserialization can fail at any moment.

objectstore-options wraps sentry-options with a typed, infallible interface:

  • Typed access — options are deserialized once into a concrete Options struct; callers borrow fields directly without knowing option names or schema layout.
  • Infallible readsOptions::get() always returns the last successfully loaded snapshot. A refresh failure logs a warning but keeps the previous values; the call site can never observe an error.
  • Borrow, don't clone — complex values and strings are borrowed from the Arc<Options> snapshot, so read-heavy paths pay no allocation cost.
  • No internal panics — the load path returns Result; init() fails loudly at startup if the initial snapshot can't be deserialized, and no .unwrap() is hidden in production paths.

In test builds the testing feature replaces Options::get() with a path that reads directly from schema defaults and the thread-local override mechanism from sentry-options, so unit tests work without calling init().

The second commit wires killswitches into this: the static YAML-configured switches and the live options switches are merged at match time, so both sources work during the rollout period.


Two follow-ups are planned but out of scope here:

  • Derive the schema.json from Rust types at compile time instead of maintaining it by hand.
  • Extract the generic initialization/refresh boilerplate and provide a derive macro for the deserialization step.

jan-auer added 2 commits April 7, 2026 17:57
…ry-options support

Introduces the `objectstore-options` crate, which wraps `sentry-options` and exposes
Objectstore-specific runtime configuration. Includes:

- `Options` struct with a global `OnceLock<RwLock<Options>>` snapshot refreshed every 5s
- `init()` function that loads an initial snapshot and spawns a background refresh task
- `Killswitch` type (plain data, deserialized from options) with usecase, scopes, and service fields
- Test-mode `Options::get()` that deserializes fresh from a thread-local instance, enabling
  `sentry_options::testing::override_options` to work without calling `init()`
- Objectstore killswitches JSON schema added to `sentry-options/schemas/objectstore/`
- `objectstore_options::init(None)` wired into the server CLI startup path
- Wire objectstore-options into objectstore-server killswitches, replacing
  the static config-backed implementation with live-reloading via sentry-options
- Switch objectstore-options global to OnceLock<ArcSwap<Options>> for lock-free reads
- Patch sentry-options to feat/additional-properties-map-schema branch to support
  object-typed schema fields with additionalProperties
@linear-code
Copy link
Copy Markdown

linear-code bot commented Apr 9, 2026

jan-auer added 2 commits April 9, 2026 13:17
…stale comment

Only spawn the background refresh task when OPTIONS.set() succeeds, so
concurrent callers cannot produce multiple refresh tasks and filesystem
watchers. Also remove a low-value inline comment in killswitches.rs.
@jan-auer jan-auer changed the title feat(options): Add objectstore-options crate feat(options): Add runtime options for killswitches Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant