A Read-Write Proxy for Connections; Also provides an ActiveRecord adapter.
A Read-Write Proxy for Connections; Also provides an ActiveRecord adapter.
We are looking for maintainers to oversee the support and development of Makara. We are no longer using Makara at Instacart and we are unable to dedicate the time and resources to maintain it.
If you're interested in maintaining Makara, please respond to this issue
Makara is generic primary/replica proxy. It handles the heavy lifting of managing, choosing, blacklisting, and cycling through connections. It comes with an ActiveRecord database adapter implementation.
Use the current version of the gem from rubygems in your Gemfile.
gem 'makara'
If you're only interested in the ActiveRecord database adapter... here you go.
Makara provides a base proxy class which you should inherit from. Your proxy connection class should implement a connection_for instance method which will be provided with an individual configuration and expect a real connection back.
class MyAwesomeSqlProxy
- role: replica
url:
Important: Do NOT use ENV['DATABASE_URL'], as it inteferes with the the database configuration
initialization and may cause Makara not to complete the configuration. For the moment, it is easier
to use a different ENV variable than to hook into the database initialization in all the supported
Rails.
For more information on url parsing, as used in ConfigParser, see:
To enable Makara to catch and handle custom errors gracefully (blacklist the connection instead of raising directly), you must add your custom matchers to the connection_error_matchers setting of your config file, for example:
production:
adapter: 'mysql2_makara'
makara:
blacklist_duration: 5
connection_error_matchers:
- !ruby/regexp '/^ActiveRecord::StatementInvalid: Mysql2::Error: Unknown command:/'
- '/Sql Server Has Gone Away/'
- 'Mysql2::Error: Duplicate entry'
You can provide strings or regexes. In the case of strings, if they start with / and end with / they will be converted to regexes when evaluated. Strings that don't start and end with / will get evaluated with standard comparison.
On occasion your app may deal with a situation where makara is not present during a write but a read should use primary. In the generic proxy details above you are encouraged to use stick_to_primary! to accomplish this. Here's an example:
# some third party creates a resource in your db, replication may not have completed yet
# ...
# then your app is told to read the resource.
def handle_request_after_third_party_record_creation
CreatedResourceClass.connection.stick_to_primary!
CreatedResourceClass.find(params[:id]) # will go to the primary
end
No open issues yet, or sync has not completed.