https://github.com/salsify/activerecord-forbid_implicit_connection_checkout
Optionally prevent threads from checking out out an ActiveRecord connection
https://github.com/salsify/activerecord-forbid_implicit_connection_checkout
gem
Last synced: 11 months ago
JSON representation
Optionally prevent threads from checking out out an ActiveRecord connection
- Host: GitHub
- URL: https://github.com/salsify/activerecord-forbid_implicit_connection_checkout
- Owner: salsify
- License: mit
- Created: 2018-01-19T18:52:05.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2025-03-11T13:09:40.000Z (over 1 year ago)
- Last Synced: 2025-07-27T09:38:42.409Z (11 months ago)
- Topics: gem
- Language: Ruby
- Homepage:
- Size: 39.1 KB
- Stars: 2
- Watchers: 36
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
[][circleci]
# ActiveRecord-ForbidImplicitCheckout
This gem allows a `Thread` to prevent itself from checking out out an ActiveRecord connection. This can be useful
in preventing your application from accidentally checking out more connections than the database can handle.
Inspired by this blog post: https://bibwild.wordpress.com/2014/07/17/activerecord-concurrency-in-rails4-avoid-leaked-connections/
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'activerecord-forbid_implicit_checkout'
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install activerecord-forbid_implicit_checkout
## Usage
```ruby
require 'active_record-forbid_implicit_connection_checkout'
Thread.new do
ActiveRecord::Base.forbid_implicit_connection_checkout_for_thread!
# Code that doesn't require ActiveRecord
end
```
If your thread needs a connection at some point
```ruby
Thread.new do
ActiveRecord::Base.forbid_implicit_connection_checkout_for_thread!
# Code that doesn't require ActiveRecord
ActiveRecord::Base.connection_pool.with_connection do
# Allow the thread to take a connection within this block
ActiveRecord::Base.connection
end
# Code that doesn't require ActiveRecord
end
```
## Why
Consider the following initially:
```ruby
require 'active_record-forbid_implicit_connection_checkout'
class Foo
def self.download(id)
Net::HTTP.get(URI("http://example.com/products/#{URI.encode(id)}"))
end
end
class Downloader
def download_all(ids)
threads = ids.map do |id|
Thread.new do
ActiveRecord::Base.forbid_implicit_connection_checkout_for_thread!
Foo.download
end
end
threads.each(&:join)
end
end
Downloader.download_all([1,2,3,4,5])
```
The developer initially designed this parallel downloading to not be dependent on the database, so the developer feels confident in running
many parallel processes of `Downloader.download_all`.
However, `Foo.download` might be subject to change.
```ruby
class SomeModel < ApplicationRecord
# ...
end
class Foo
def self.download(id)
id = SomeModel.find(id).alias_id
Net::HTTP.get(URI("http://example.com/products/#{URI.encode(id)}"))
end
end
```
After this modification to `Foo.download`, each thread will checkout a new connection to the database. Which could
overwhelm the database if there are many parallel processes executing `Downloader.download_all`. While this violates,
the initial assumption about `Downloader.download_all` using the database, it would have been useful to have a safeguard to prevent
this situation from occurring.
The error generated by setting `ActiveRecord::Base.forbid_implicit_connection_checkout_for_thread!` could have detected
this situation during testing which should have failed with `ActiveRecord::ImplicitConnectionForbiddenError`. In the
worst case, the production code running this would have failed with `ActiveRecord::ImplicitConnectionForbiddenError`,
but it would have prevented the database from being overwhelmed and have protected the rest of the application.
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then,
run `rake spec` to run the tests. You can also run `bin/console` for an
interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run `bundle exec rake install`.
To release a new version, update the version number in `version.rb`, and then
run `bundle exec rake release`, which will create a git tag for the version,
push git commits and tags, and push the `.gem` file to
[rubygems.org](https://rubygems.org)
.
## Contributing
Bug reports and pull requests are welcome on GitHub at
https://github.com/salsify/activerecord-forbid_implicit_checkout.## License
The gem is available as open source under the terms of the
[MIT License](http://opensource.org/licenses/MIT).