An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          

[![Build Status](https://circleci.com/gh/salsify/activerecord-forbid_implicit_connection_checkout.svg?style=svg)][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).