diff --git a/sentry-ruby/falcon-fiber-hub/.mise.toml b/sentry-ruby/falcon-fiber-hub/.mise.toml new file mode 100644 index 0000000..8159c4c --- /dev/null +++ b/sentry-ruby/falcon-fiber-hub/.mise.toml @@ -0,0 +1,6 @@ +[tools] +ruby = "3.3" + +[tasks.serve] +description = "Run the Falcon repro server" +run = "bundle exec falcon serve -b http://localhost:9292 --count 1 --threaded" diff --git a/sentry-ruby/falcon-fiber-hub/Gemfile b/sentry-ruby/falcon-fiber-hub/Gemfile new file mode 100644 index 0000000..e544967 --- /dev/null +++ b/sentry-ruby/falcon-fiber-hub/Gemfile @@ -0,0 +1,8 @@ +source "https://rubygems.org" + +# Point at the local checkout / branch under development (feat/fiber-hub-storage) +gem "sentry-ruby", path: "/Users/neel/sentry/sdks/sentry-ruby/sentry-ruby" + +gem "falcon" +gem "async" +gem "debug" diff --git a/sentry-ruby/falcon-fiber-hub/Gemfile.lock b/sentry-ruby/falcon-fiber-hub/Gemfile.lock new file mode 100644 index 0000000..133f686 --- /dev/null +++ b/sentry-ruby/falcon-fiber-hub/Gemfile.lock @@ -0,0 +1,180 @@ +PATH + remote: /Users/neel/sentry/sdks/sentry-ruby/sentry-ruby + specs: + sentry-ruby (6.6.2) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + logger + +GEM + remote: https://rubygems.org/ + specs: + async (2.42.0) + console (~> 1.29) + fiber-annotation + io-event (~> 1.11) + metrics (~> 0.12) + traces (~> 0.18) + async-container (0.37.0) + async (~> 2.22) + async-http (0.95.1) + async (>= 2.10.2) + async-pool (~> 0.11) + io-endpoint (~> 0.14) + io-stream (~> 0.6) + metrics (~> 0.12) + protocol-http (~> 0.62) + protocol-http1 (~> 0.39) + protocol-http2 (~> 0.26) + protocol-url (~> 0.2) + traces (~> 0.10) + async-http-cache (0.4.6) + async-http (~> 0.56) + async-pool (0.11.2) + async (>= 2.0) + async-service (0.24.1) + async + async-container (~> 0.34) + string-format (~> 0.2) + async-utilization (0.4.0) + console (~> 1.0) + bake (0.25.0) + bigdecimal + samovar (~> 2.1) + bigdecimal (4.1.2) + concurrent-ruby (1.3.7) + console (1.37.0) + fiber-annotation + fiber-local (~> 1.1) + json + debug (1.11.1) + irb (~> 1.10) + reline (>= 0.3.8) + erb (6.0.4) + falcon (0.55.5) + async + async-container (~> 0.20) + async-http (~> 0.75) + async-http-cache (~> 0.4) + async-service (~> 0.19) + async-utilization (~> 0.3) + bundler + localhost (~> 1.1) + openssl (>= 3.0) + protocol-http (~> 0.31) + protocol-rack (~> 0.7) + samovar (~> 2.3) + fiber-annotation (0.2.0) + fiber-local (1.1.0) + fiber-storage + fiber-storage (1.0.1) + io-console (0.8.2) + io-endpoint (0.17.2) + io-event (1.19.2) + io-stream (0.13.2) + openssl (>= 3.3) + irb (1.18.0) + pp (>= 0.6.0) + prism (>= 1.3.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + json (2.21.1) + localhost (1.8.0) + bake + logger (1.7.0) + metrics (0.15.0) + openssl (4.0.2) + pp (0.6.4) + prettyprint + prettyprint (0.2.0) + prism (1.9.0) + protocol-hpack (1.5.1) + protocol-http (0.63.0) + protocol-http1 (0.39.0) + protocol-http (~> 0.62) + protocol-http2 (0.26.0) + protocol-hpack (~> 1.4) + protocol-http (~> 0.62) + protocol-rack (0.22.1) + io-stream (>= 0.10) + protocol-http (~> 0.58) + rack (>= 1.0) + protocol-url (0.4.0) + rack (3.2.6) + rbs (4.0.3) + logger + prism (>= 1.6.0) + tsort + rdoc (8.0.0) + erb + prism (>= 1.6.0) + rbs (>= 4.0.0) + tsort + reline (0.6.3) + io-console (~> 0.5) + samovar (2.5.1) + console (~> 1.0) + string-format (0.2.0) + traces (0.18.2) + tsort (0.2.0) + +PLATFORMS + arm64-darwin-23 + ruby + +DEPENDENCIES + async + debug + falcon + sentry-ruby! + +CHECKSUMS + async (2.42.0) sha256=536078293b8c95d5b5679fa01bf7d2458bcc65cd46dec2c4cb3580feaeb965c6 + async-container (0.37.0) sha256=16bd50a6d3ba818d917160a96a965a2cde0fd0e9959715741cbeeba90d68d315 + async-http (0.95.1) sha256=0c3dd458c204c06d5c4b20b01bbec4794a1203db627fb2ce536e1799ec14786c + async-http-cache (0.4.6) sha256=2038d1f093182f16b50b4db271c25085e3938da10bfcfc2904cadb0530fddfd6 + async-pool (0.11.2) sha256=0a43a17b02b04d9c451b7d12fafa9a50e55dc6dd00d4369aca00433f16a7e3ed + async-service (0.24.1) sha256=3ee313fa2d6c1427ffac68f42f272889c496fa1088cf1432b1e7a5f5bff56b06 + async-utilization (0.4.0) sha256=4da53cb1733a12c9cf70ff22bd37d29c10fa9162a03ddb10f34e12acd171fe32 + bake (0.25.0) sha256=a47bdc6a26addc048827debc36fe27bb4d5d71ac2958ad910b5386e9baf49869 + bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd + bundler (4.0.15) sha256=a4ceb882fe94a0e0ac63cd0813932bbfd631a14e5ac0b7975189b19a4d28d9e7 + concurrent-ruby (1.3.7) sha256=4412caec3a5ea2e5fdc52076724c071a81f2c0593d83b2ac8cbb8ca63b3151b0 + console (1.37.0) sha256=8093b286c2595a063849c098594fee5155ecc7967d36f3aa8cbe7569c8f3efd7 + debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6 + erb (6.0.4) sha256=38e3803694be357fe2bfe312487c74beaf9fb4e5beb3e22498952fe1645b95d9 + falcon (0.55.5) sha256=8622db11361b6678578dd7e06b953aaef10e5006929ced618069bb62b0ff118d + fiber-annotation (0.2.0) sha256=7abfadf1d119f508867d4103bf231c0354d019cc39a5738945dec2edadaf6c03 + fiber-local (1.1.0) sha256=c885f94f210fb9b05737de65d511136ea602e00c5105953748aa0f8793489f06 + fiber-storage (1.0.1) sha256=f48e5b6d8b0be96dac486332b55cee82240057065dc761c1ea692b2e719240e1 + io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc + io-endpoint (0.17.2) sha256=3feaf766c116b35839c11fac68b6aaadc47887bb488902a57bf8e1d288fb3338 + io-event (1.19.2) sha256=c9ac4f0c3153b453727ab15c03cc762b29a207979c703b2bb15c8be6209d4b4c + io-stream (0.13.2) sha256=8c7ac4efbb0d91d951726bbc88dbf28a56f792ff388e82bb18aa5abc48f2fe36 + irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3 + json (2.21.1) sha256=13a43df75d95641443f5702dff350f237164a9d811ff0f2c2800d4d980220583 + localhost (1.8.0) sha256=df7ea825b4f64949c588c17efac86bc47ddc4460d723778abe933b71759b2701 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + metrics (0.15.0) sha256=61ded5bac95118e995b1bc9ed4a5f19bc9814928a312a85b200abbdac9039072 + openssl (4.0.2) sha256=1037ad2868ae58df9ad917891c0c0f9815a1172f6846d4bcdd508e4c2ee747c2 + pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570 + prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 + prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85 + protocol-hpack (1.5.1) sha256=6feca238b8078da1cd295677d6f306c6001af92d75fe0643d33e6956cbc3ad91 + protocol-http (0.63.0) sha256=7e94958cbdc20e9d9b4ecb1959e1e7824a35f36e082d3d2cd5bd844da643a8e4 + protocol-http1 (0.39.0) sha256=e49b3f4cda6f5d94c76a323d2b7f6977cba3ebd082d2da437039594da77ad8eb + protocol-http2 (0.26.0) sha256=bac89cd78082b241ccd0cf7246f5160e4bb0c9c975fb4bf7deef5f88cc317486 + protocol-rack (0.22.1) sha256=1185d245927ef9849a603700d6991ca353bc89724fbf98efa4a4333ed62a9fc3 + protocol-url (0.4.0) sha256=64d4c03b6b51ad815ac6fdaf77a1d91e5baf9220d26becb846c5459dacdea9e1 + rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2 + rbs (4.0.3) sha256=5a7bf70e2628549d9a1f44eae447b2cfe55968a9c60cfff52693a4bdcc020e14 + rdoc (8.0.0) sha256=03bf8c08a9639658855a0cfd77c0abca8325c227693f7f33f82957811348c469 + reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835 + samovar (2.5.1) sha256=8a9fc41eb8868084f0321eb41678c485cfbc7d282fb306c0be67c3284b1d2394 + sentry-ruby (6.6.2) + string-format (0.2.0) sha256=bc981c14116b061f12134549f32fa2d61a17b5a35dd6fd36596c21722a789af6 + traces (0.18.2) sha256=80f1649cb4daace1d7174b81f3b3b7427af0b93047759ba349960cb8f315e214 + tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f + +BUNDLED WITH + 4.0.15 diff --git a/sentry-ruby/falcon-fiber-hub/README.md b/sentry-ruby/falcon-fiber-hub/README.md new file mode 100644 index 0000000..ed6043e --- /dev/null +++ b/sentry-ruby/falcon-fiber-hub/README.md @@ -0,0 +1,25 @@ +# Falcon + fiber hub storage repro + +Exercises `config.hub_isolation_level` (branch `feat/fiber-hub-storage`) under a +real fiber-per-request server. Falcon schedules concurrent requests as sibling +fibers on one reactor thread, so a request that yields mid-flight lets its +siblings run. With `:thread` storage they share one hub and stomp each other's +scope; with `:fiber` storage each request keeps its own. + +Ruby is pinned via `.mise.toml`; prefix commands with `mise exec --`. + +## Setup + +```bash +mise install +mise exec -- bundle install +``` + +## Run + +```bash +mise run serve & + +# hammer it with interleaved ids +seq 0 20 | xargs -P 20 -I{} curl -s "http://localhost:9292/?id={}" +``` diff --git a/sentry-ruby/falcon-fiber-hub/config.ru b/sentry-ruby/falcon-fiber-hub/config.ru new file mode 100644 index 0000000..70885cd --- /dev/null +++ b/sentry-ruby/falcon-fiber-hub/config.ru @@ -0,0 +1,31 @@ +require "debug" +require "sentry-ruby" + +level = :fiber # :thread to see tag mismatch + +Sentry.init do |config| + config.release = "falcon-fiber" + config.sdk_logger.level = :debug + config.hub_isolation_level = level + config.traces_sample_rate = 1.0 +end + +# CaptureExceptions clones a fresh hub per request and wraps it in its own scope. +# Falcon runs concurrent requests as sibling fibers on a single reactor thread, +# so a request that yields mid-flight (here a `sleep`) lets its siblings run. +# With :thread storage those siblings share one hub and clobber each other's +# scope; with :fiber storage each request keeps its own. +use Sentry::Rack::CaptureExceptions + +run(lambda do |env| + req = Rack::Request.new(env) + id = req.params["id"].to_i + + Sentry.set_tags(id: id) + + sleep 0.05 # yield to the reactor so a sibling fiber overwrites the shared hub + + # The exception rides in the raising fiber, so its message stays truthful even + # when the hub (and thus the `id` tag) has been clobbered by a sibling. + raise "request level=#{level} id=#{id}" +end)