Rails 8 rate_limit and Solid Cache do not compose: the lost first increment
https://launchkit.codes/yield/rails-without-redis
Rails 8’s rate_limit defaults to your cache store, and Solid Cache increments through SELECT ... FOR UPDATE, which locks nothing when the row does not exist yet. Two concurrent first increments of a key both read nil and both write 1, so a limit of ten admits eleven, once per first-seen identifier.
Also covers why the race is narrower than it first looks: an expired entry keeps its row, and trimming defaults to a two-week max_age, so only a genuinely absent row is exposed.
Read against solid_cache 1.0.10 and actionpack 8.1.3.1, with the gem file and version cited for every claim.
Post a comment