#451 guard Fbe::Middleware::RateLimit state with a mutex#470
Open
edmoffo wants to merge 1 commit into
Open
Conversation
Wrap the cache-refresh and counter-decrement paths in a single Mutex so concurrent callers cannot lose increments on @counter, decrements on @remaining/@searchleft, or race two threads through the cache-miss branch of /rate_limit. Drop the "NOT thread-safe" header comment that documented the prior limitation. Add two regression tests in test/fbe/middleware/test_rate_limit.rb: one fires ten threads making mixed /user and /search/issues calls and asserts both counters drop by the expected amount, and one fires twenty threads against /rate_limit on a cold cache and asserts the underlying endpoint is only hit once.
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.
Closes #451.
Fbe::Middleware::RateLimitkeeps mutable state (@cached,@remaining,@searchleft,@counter) in plain instance variables and updates them with non-atomic compound operations like@counter += 1and@remaining -= 1. The middleware instance is shared across every request through the same Faraday connection, so any concurrent caller (parallel judges, fiber-based fetches, anything that usesFbe.octofrom threads) would race on these vars and lose decrements, serve stale cached/rate_limitfor longer than the 100-request window intended, and let two threads through the cache-miss branch at the same time.The change adds a
Mutexaround the cache-refresh path inhandle_rate_limit_requestand around the counter mutation intrack_request, while keeping@app.call(env)outside the lock so a slow downstream request does not serialize unrelated callers. The "NOT thread-safe" header comment that documented the prior limitation is gone.Local validation against ruby 3.3.6 on linux:
bundle exec rake test TEST=test/fbe/middleware/test_rate_limit.rb— 16 tests, 32 assertions, 0 failures, 0 errors, including the two new regression teststest_concurrent_non_rate_limit_requests_do_not_lose_decrementsandtest_concurrent_rate_limit_requests_refresh_once.bundle exec rake test— 275 tests, 760 assertions, 0 new failures (10 pre-existing errors intest_octo.rband adjacent quota-dependent tests reproduce onmasterin this environment and are unrelated to this change).bundle exec rake rubocop— 65 files inspected, no offenses.bundle exec rake yard— 81.82% documented, no new warnings.