feat(options): Auto-generate sentry-options schema from Rust types#426
Draft
jan-auer wants to merge 15 commits into
Draft
feat(options): Auto-generate sentry-options schema from Rust types#426jan-auer wants to merge 15 commits into
jan-auer wants to merge 15 commits into
Conversation
…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
…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.
* origin/main: (99 commits) fix(server): Ignore client-supplied read-only metadata on writes (#535) fix(stresstest): Use `put_path` for `many` requests (#533) fix(server): Strip Kubernetes hashes from downstream service (#530) ci: Scope sentry-options secrets instead of inherit (#534) build(client): Remove version pin notice on tokio dependency (#531) ref(server): Capture errors from backend servers in Sentry (#525) fix(server): Remove service tag from request metric (#528) fix(sentry): Bind hub to response bodies via middleware (#526) build: Disable in-process symbolication for heap profiles (#527) fix(dev): Only pass profiling feature for objectstore-server (#523) feat(server): Add on-demand heap profiling endpoints (#522) feat: Add filename field to Metadata (#517) docs: Fix and expand documentation across the workspace (#521) fix: Replace lossy casts with safer integer idioms (#518) build(deps): bump sentry to 0.48.3 (#520) ref(server): Skip auth checks when not configured (#519) feat(client): Accept optional tokens in ClientBuilder::token (#516) fix: Remove needless return statements in tiered backend tests (#514) fix: Use jemalloc only on linux (#515) fix: Apply pedantic Clippy lints across workspace (#513) ... # Conflicts: # Cargo.lock # Cargo.toml # README.md # objectstore-server/Cargo.toml # objectstore-server/src/extractors/id.rs # objectstore-server/src/killswitches.rs # objectstore-server/tests/limits.rs
Replace the tokio-spawned polling loop with a propagation callback registered via InitBuilder, and switch to the feat/expose-builder-build branch of sentry-options. Bump arc-swap and lru accordingly. WIP: refresh() still references the built `inner` instance, which is no longer in scope — the callback needs a path to reach it. Does not compile.
Introduces two new crates that replace the hand-written boilerplate in objectstore-options: - `objectstore-typed-options` — defines the `SentryOptions` trait, the shared `Error` type, and the generic background `refresh` loop. All dependencies consumed by generated code (arc-swap, serde, serde_json, sentry-options, tokio) are re-exported as hidden items so consumers do not need to declare them directly. Exposes a `derive` feature that re-exports the proc macro. - `objectstore-typed-options-derive` — provides `#[derive(SentryOptions)]`, which generates the global OnceLock singleton, trait impl, `get()`, `init()`, and (under the `testing` feature) `override_with()`. All generated paths are fully qualified through `objectstore_typed_options`, so the derive can be used from any crate. `objectstore-options` is reduced to the concrete struct definitions: - Its dependency list shrinks to `objectstore-typed-options` (with the `derive` feature) and `serde`. - The `init()` free function is gone; callers use `Options::init()`.
Two structs deriving SentryOptions in the same module previously produced
a duplicate symbol error because __OPTIONS was emitted at module scope with
a fixed name. Wrapping all generated items in const _: () = { … } gives
each derived struct its own anonymous scope, matching the standard
serde-style hygiene idiom.
jan-auer
force-pushed
the
feat/sentry-options-derive
branch
from
July 6, 2026 08:37
d48e54d to
db06791
Compare
Add schema generation support to objectstore-typed-options so the sentry-options schema stays in sync with the Rust struct definitions. Previously the schema was hand-written and had already drifted. The conversion logic lives in objectstore_typed_options::schema and is gated behind the testing feature. Consumers add JsonSchema derives (also test-only) and call assert_schema_matches_golden_file in a single test. The schema remains checked in so sentry-options-automator can access it without running Rust, and so reviewers can inspect schema changes in PRs. The golden file test catches drift immediately and prints a colored unified diff; UPDATE_SCHEMA=1 regenerates it. Co-Authored-By: Claude <noreply@anthropic.com>
jan-auer
force-pushed
the
feat/options-schema-gen
branch
from
July 6, 2026 10:38
db98af4 to
3c84c44
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat/sentry-options-derive #426 +/- ##
==============================================================
- Coverage 87.33% 87.08% -0.25%
==============================================================
Files 92 93 +1
Lines 14534 14564 +30
==============================================================
- Hits 12693 12683 -10
- Misses 1841 1881 +40
☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
jan-auer
force-pushed
the
feat/sentry-options-derive
branch
3 times, most recently
from
July 8, 2026 15:59
29d2057 to
46ce99d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
This is a proof-of-concept showcase, not intended for merge here. The implementation belongs in the
sentry-optionsrepo once #425 has landed there. This PR exists to demonstrate the approach and invite feedback before that upstream work begins. It has been written with Claude Code and the code has not been cleaned up or improved yet.Stacked on #425.
The
sentry-options/schemas/objectstore/schema.jsonwas hand-written and had already drifted out of sync with the Rust types. This introduces auto-generation so the schema is always derived from the source of truth.Approach
schemarsderivesJsonSchemaon the options struct and its nested types (test-only, so schemars stays out of the production binary). A conversion function inobjectstore-typed-options::schematranslates the schemars output into sentry-options format, applying the per-level rules that format enforces —descriptionanddefaultonly at top-level properties,optionalonly in nested item properties, no description or default deeper in the tree.The schema file remains checked in for two reasons:
sentry-options-automatorneeds access to it without running Rust, and reviewers can see schema changes directly in PRs without running anything locally.Drift detection
A thin golden-file test in
objectstore-optionscallsassert_schema_matches_golden_file::<Options>()from the shared library. When the schema is out of date, the test fails with a colored unified diff so the delta is immediately readable. To regenerate:Adding or renaming a field, changing a doc comment, or adjusting optionality will all cause the test to fail with a precise diff pointing at exactly what changed.
What lives where
objectstore-typed-options::schema— reusable conversion and assertion logic; activated by thetestingfeatureobjectstore-options— one test, one path construction; everything else is in the library