Giter VIP home page Giter VIP logo

makara's Introduction

Makara

Build Status Gem Version Code Climate

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.

Installation

Use the current version of the gem from rubygems in your Gemfile.

gem 'makara'

Basic Usage

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 < ::Makara::Proxy
  def connection_for(config)
    ::Sql::Client.new(config)
  end
end

Next, you need to decide which methods are proxied and which methods should be sent to all underlying connections:

  # within MyAwesomeSqlProxy
  hijack_method :select, :ping
  send_to_all :connect, :reconnect, :disconnect, :clear_cache

Assuming you don't need to split requests between a primary and a replica, you're done. If you do need to, implement the needs_primary? method:

  # within MyAwesomeSqlProxy
  def needs_primary?(method_name, args)
    return false if args.empty?
    sql = args.first
    sql !~ /^select/i
  end

This implementation will send any request not like "SELECT..." to a primary connection. There are more methods you can override and more control over blacklisting - check out the makara database adapter for examples of advanced usage.

Config Parsing

Makara comes with a config parser which will handle providing subconfigs to the connection_for method. Check out the ActiveRecord database.yml example below for more info.

Stickiness Context

Makara handles stickiness by keeping track of which proxies are stuck at any given moment. The context is basically a mapping of proxy ids to the timestamp until which they are stuck.

To handle persistence of context across requests in a Rack app, makara provides a middleware. It lays a cookie named _mkra_stck which contains the current context. If the next request is executed before the cookie expires, that given context will be used. If something occurs which naturally requires the primary on the second request, the context is updated and stored again.

Stickiness Impact

When sticky:true, once a query as been sent to the primary, all queries for the rest of the request will also be sent to the primary. In addition, the cookie described above will be set client side with an expiration defined by time at end of original request + primary_ttl. As long as the cookie is valid, all requests will send queries to primary.

When sticky:false, only queries that need to go to the primary will go there. Subsequent read queries in the same request will go to replicas.

Releasing stuck connections (clearing context)

If you need to clear the current context, releasing any stuck connections, all you have to do is:

Makara::Context.release_all

You can also clear stuck connections for a specific proxy:

Makara::Context.release(proxy_id)
Makara::Context.release('mysql_main')
Makara::Context.release('redis')
...

A context is local to the curent thread of execution. This will allow you to stick to the primary safely in a single thread in systems such as sidekiq, for instance.

Forcing Primary

If you need to force the primary in your app then you can simply invoke stick_to_primary! on your connection:

persist = true # or false, it's true by default
proxy.stick_to_primary!(persist)

It'll keep the proxy stuck to the primary for the current request, and if persist = true (default), it'll be also stored in the context for subsequent requests, keeping the proxy stuck up to the duration of primary_ttl configured for the proxy.

Skipping the Stickiness

If you're using the sticky: true configuration and you find yourself in a situation where you need to write information through the proxy but you don't want the context to be stuck to the primary, you should use a without_sticking block:

proxy.without_sticking do
  # do my stuff that would normally cause the proxy to stick to the primary
end

Logging

You can set a logger instance to ::Makara::Logging::Logger.logger and Makara will log how it handles errors at the Proxy level.

Makara::Logging::Logger.logger = ::Logger.new(STDOUT)

ActiveRecord Database Adapter

So you've found yourself with an ActiveRecord-based project which is starting to get some traffic and you realize 95% of you DB load is from reads. Well you've come to the right spot. Makara is a great solution to break up that load not only between primary and replica but potentially multiple primaries and/or multiple replicas.

By creating a makara database adapter which simply acts as a proxy we avoid any major complexity surrounding specific database implementations. The makara adapter doesn't care if the underlying connection is mysql, postgresql, etc it simply cares about the sql string being executed.

What goes where?

In general: Any SELECT statements will execute against your replica(s), anything else will go to the primary.

There are some edge cases:

  • SET operations will be sent to all connections
  • Execution of specific methods such as connect!, disconnect!, and clear_cache! are invoked on all underlying connections
  • Calls inside a transaction will always be sent to the primary (otherwise changes from within the transaction could not be read back on most transaction isolation levels)
  • Locking reads (e.g. SELECT ... FOR UPDATE) will always be sent to the primary

Errors / blacklisting

Whenever a node fails an operation due to a connection issue, it is blacklisted for the amount of time specified in your database.yml. After that amount of time has passed, the connection will begin receiving queries again. If all replica nodes are blacklisted, the primary connection will begin receiving read queries as if it were a replica. Once all nodes are blacklisted the error is raised to the application and all nodes are whitelisted.

Database.yml

Your database.yml should contain the following structure:

production:
  adapter: 'mysql2_makara'
  database: 'MyAppProduction'
  # any other standard AR configurations

  # add a makara subconfig
  makara:

    # optional id to identify the proxy with this configuration for stickiness
    id: mysql
    # the following are default values
    blacklist_duration: 5
    primary_ttl: 5
    primary_strategy: round_robin
    sticky: true

    # list your connections with the override values (they're merged into the top-level config)
    # be sure to provide the role if primary, role is assumed to be a replica if not provided
    connections:
      - role: primary
        host: primary.sql.host
      - role: replica
        host: replica1.sql.host
      - role: replica
        host: replica2.sql.host

Let's break this down a little bit. At the top level of your config you have the standard adapter choice. Currently the available adapters are listed in lib/active_record/connection_adapters/. They are in the form of #{db_type}_makara where db_type is mysql, postgresql, etc.

Following the adapter choice is all the standard configurations (host, port, retry, database, username, password, etc). With all the standard configurations provided, you can now provide the makara subconfig.

The makara subconfig sets up the proxy with a few of its own options, then provides the connection list. The makara options are:

  • id - an identifier for the proxy, used for sticky behaviour and context. The default is to use a MD5 hash of the configuration contents, so if you are setting sticky to true, it's a good idea to also set an id. Otherwise any stuck connections will be cleared if the configuration changes (as the default MD5 hash id would change as well)
  • blacklist_duration - the number of seconds a node is blacklisted when a connection failure occurs
  • disable_blacklist - do not blacklist node at any error, useful in case of one primary
  • sticky - if a node should be stuck to once it's used during a specific context
  • primary_ttl - how long the primary context is persisted. generally, this needs to be longer than any replication lag
  • primary_strategy - use a different strategy for picking the "current" primary node: failover will try to keep the same one until it is blacklisted. The default is round_robin which will cycle through available ones.
  • replica_strategy - use a different strategy for picking the "current" replica node: failover will try to keep the same one until it is blacklisted. The default is round_robin which will cycle through available ones.
  • connection_error_matchers - array of custom error matchers you want to be handled gracefully by Makara (as in, errors matching these regexes will result in blacklisting the connection as opposed to raising directly).

Connection definitions contain any extra node-specific configurations. If the node should behave as a primary you must provide role: primary. Any previous configurations can be overridden within a specific node's config. Nodes can also contain weights if you'd like to balance usage based on hardware specifications. Optionally, you can provide a name attribute which will be used in sql logging.

connections:
  - role: primary
    host: myprimary.sql.host
    blacklist_duration: 0

  # implicit role: replica
  - host: mybigreplica.sql.host
    weight: 8
    name: Big Replica
  - host: mysmallreplica.sql.host
    weight: 2
    name: Small Replica

In the previous config the "Big Replica" would receive ~80% of traffic.

DATABASE_URL

Connections may specify a url parameter in place of host, username, password, etc.

connections:
  - role: primary
    blacklist_duration: 0
    url: 'mysql2://db_username:db_password@localhost:3306/db_name'

We recommend, if using environmental variables, to interpolate them via ERb.

connections:
  - role: primary
    blacklist_duration: 0
    url: <%= ENV['DATABASE_URL_PRIMARY'] %>
  - role: replica
    url: <%= ENV['DATABASE_URL_REPLICA'] %>

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:

Custom error matchers:

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.

Common Problems / Solutions

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

Todo

  • Support for providing context as query param
  • More real world examples

makara's People

Contributors

ankane avatar bf4 avatar bleonard avatar davidjairala avatar dependabot[bot] avatar drakula2k avatar evantahler avatar georgeclaghorn avatar ilstar avatar jcraigk avatar jeremy avatar kdonovan avatar kevinrob avatar kinopyo avatar mcansky avatar mlarraz avatar mnelson avatar montanalow avatar natematykiewicz avatar nikai3d avatar nobodysnightmare avatar ota42y avatar overlycommonname avatar pauldowman avatar prburgu avatar righi avatar rosa avatar thewudu avatar tonkonozhenko avatar yatish27 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

makara's Issues

Newrelic RPM Performance Regression

Issues #45 and #51 have both reported issues when using Makara alongside certain versions of newrelic/rpm. In an attempt to be as transparent as possible as well as potentially isolate the issue, the following table will hold the information required to check your stack against other community reports.

Newrelic has released a fix

The range of newrelic releases affected is 3.7.2 <= X < 3.11.2

Makara Version AR Version RPM Version Regression
0.0.x 3.2 3.6.9 no
0.2.x 4.x 3.6.5.130 no
0.2.x 4.x 3.6.6.147 no
0.3.x 4.x 3.6.6.147 no
BROKE --- --- ---
0.2.x 4.x 3.7.2 yes
0.2.x 4.x 3.9.4.245 yes
0.3.x 4.x 3.8.1.221 yes
0.3.x 4.x 3.9.5.251 yes
0.3.x 4.x 3.9.6.257 yes
0.3.x 4.x 3.9.7.266 yes
FIXED --- --- ---
0.x.x x.x 3.11.2 no

makara_adapter: method_missing forces master too often

hi,

i just started playing around with your awesome looking makara gem. but i had some troubles getting it to work as i expected.

i used the current master (3455850) and compared it with the tag v0.1.0.beta4.

setup

      adapter: makara_mysql2

      sticky_master:      false
      sticky_slave:       false
      blacklist_duration: 60
      verbose:            true

      database: development
      port:     3306
      encoding: utf8   # not sure if these two settings

      connections:
        - name: db
          role: master
          host: localhost
          username: root
          password: root


        - name: dbslave01
          role: slave
          host: localhost
          username: root
          password: root
          weight: 3

this is what i did

User.all

on master i get

  [default/db] SCHEMA (1.2ms)  SHOW FULL FIELDS FROM `users`
  [default/db] SCHEMA (0.3ms)  SHOW TABLES LIKE 'users'
  [default/db] User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`deleted_at` IS NULL

on v0.1.0.beta4 i get

  [db] SCHEMA (1.8ms)  SHOW FULL FIELDS FROM `users`
  [dbslave01] SCHEMA (0.4ms)  SHOW TABLES LIKE 'users'
  [dbslave01] User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`deleted_at` IS NULL

i tried to debug this and with some debug output i found that the problem might be related with the method_missing method in makara_adapter.rb.

it looks like if you call methods using the with_master block which forces makara to use the master connection. i'm not really sure hot to fix this or if this is intended behavior but i couldn't figure out how to get makara select a slave for a "select" statement.

i also played around with one of your tests (https://gist.github.com/lister/6727346) which seems to work just fine...

it would be great if you could help me.

Br, Simon

not able install gem

After giving "gem 'makara', git: '[email protected]:taskrabbit/makara.git', tag: 'v0.2.0.beta9'" in Gemfile and when does the 'bundle install' gets the following error ๐Ÿ‘

Permission denied (publickey).
fatal: Could not read from remote repository.

"Please make sure you have the correct access rights
and the repository exists.
Git error: command git clone '[email protected]:taskrabbit/makara.git' "/home/nikhilvs9999/.rvm/gems/ruby-1.9.3-p448/cache/bundler/git/makara-d929f6b77aa149f0be81a67ac1a27255af446fe3" --bare --no-hardlinks in directory /home/nikhilvs9999/RAILS/rails_aptana_workspace/api-server has failed. "

.lock! method performed on slaves instead of master

We're doing database locking in one of our API callbacks, and this has broken since moving to makara. PostgreSQL handles locking using a SELECT FOR UPDATE a la SELECT "video_representations".* FROM "video_representations" WHERE "video_representations"."id" = $1 LIMIT 1 FOR UPDATE

MakaraAbstractAdapter's regex doesn't catch this. I'm working on a fixed up regex right now but I'm a bit rusty in that department. failing that, i can work around this by doing a VideoRepresentation.touch or so to promote the request to master myself, but this is still, imo, a bug in the #needs_master method. If a single regex cannot cover this, a SQL_FORCE_MASTER regex which can catch SELECT FOR UPDATE coudl be inserted in to #needs_master, either way, I'm willing to submit the pull request for that. :)

Unsure if PostgreSQL config is working as expected

I've largely got Makara configured and working as expected, but while testing the fail-over capabilities of the slaves, I'm not seeing master take over. It's my understanding that if all the slaves become blacklisted, master should take over.

I'm able to successfully run the application using a single master and a single slave. I can see that when I modify records, the master database is used, and when I make reads, the slave is used. I'm able to bring down master and continue to read from the slave, and when I try to write, those commands fail.

However, if I leave master running and bring down my single slave, all reads fail. I believe all requests should be issued against master in this case, correct?

EDIT: When I say "bring down" I'm actually asking Postgres to gracefully shutdown....if that matters at all.

My config is as follows:


---
staging:
  adapter: makara_postgresql
  encoding: utf8
  username: cp
  password: xxxxxxxxxxx
  database: cp_staging
  makara:
    connections:
    - role: master
      host: i.mztest2.domain.com
      name: cp_master
    - role: slave
      host: i.mztest3.domain.com
      name: cp_slave

The Error I'm seeing:

could not connect to server: Connection refused Is the server running on host "i.mztest3.domain.com" (10.206.42.32) and accepting TCP/IP connections on port 5432?

activerecord (4.0.1) lib/active_record/connection_adapters/postgresql_adapter.rb:831:in `initialize'
activerecord (4.0.1) lib/active_record/connection_adapters/postgresql_adapter.rb:831:in `new'
activerecord (4.0.1) lib/active_record/connection_adapters/postgresql_adapter.rb:831:in `connect'
activerecord (4.0.1) lib/active_record/connection_adapters/postgresql_adapter.rb:548:in `initialize'
activerecord (4.0.1) lib/active_record/connection_adapters/postgresql_adapter.rb:41:in `new'
activerecord (4.0.1) lib/active_record/connection_adapters/postgresql_adapter.rb:41:in `postgresql_connection'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bundler/gems/makara-c9b067b5ada7/lib/active_record/connection_adapters/makara_postgresql_adapter.rb:35:in `connection_for'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bundler/gems/makara-c9b067b5ada7/lib/makara/proxy.rb:175:in `block in instantiate_connections'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bundler/gems/makara-c9b067b5ada7/lib/makara/proxy.rb:174:in `each'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bundler/gems/makara-c9b067b5ada7/lib/makara/proxy.rb:174:in `instantiate_connections'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bundler/gems/makara-c9b067b5ada7/lib/makara/proxy.rb:50:in `initialize'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bundler/gems/makara-c9b067b5ada7/lib/active_record/connection_adapters/makara_abstract_adapter.rb:58:in `initialize'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bundler/gems/makara-c9b067b5ada7/lib/active_record/connection_adapters/makara_postgresql_adapter.rb:8:in `new'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bundler/gems/makara-c9b067b5ada7/lib/active_record/connection_adapters/makara_postgresql_adapter.rb:8:in `makara_postgresql_connection'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:440:in `new_connection'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:450:in `checkout_new_connection'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:421:in `acquire_connection'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:356:in `block in checkout'
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:355:in `checkout'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:265:in `block in connection'
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:264:in `connection'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:546:in `retrieve_connection'
activerecord (4.0.1) lib/active_record/connection_handling.rb:79:in `retrieve_connection'
activerecord (4.0.1) lib/active_record/connection_handling.rb:53:in `connection'
activerecord (4.0.1) lib/active_record/query_cache.rb:51:in `restore_query_cache_settings'
activerecord (4.0.1) lib/active_record/query_cache.rb:43:in `rescue in call'
activerecord (4.0.1) lib/active_record/query_cache.rb:32:in `call'
activerecord (4.0.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:626:in `call'
actionpack (4.0.1) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.0.1) lib/active_support/callbacks.rb:373:in `_run__3248633690540873971__call__callbacks'
activesupport (4.0.1) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.1) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
/mnt/srv/client_portal/current/gems/apoc/lib/apoc/geo_ip/country_lookup.rb:62:in `call'
actionpack (4.0.1) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
airbrake (3.1.14) lib/airbrake/rails/middleware.rb:13:in `call'
actionpack (4.0.1) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
actionpack (4.0.1) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.0.1) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.0.1) lib/rails/rack/logger.rb:22:in `call'
actionpack (4.0.1) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
rack (1.5.2) lib/rack/runtime.rb:17:in `call'
activesupport (4.0.1) lib/active_support/cache/strategy/local_cache.rb:83:in `call'
actionpack (4.0.1) lib/action_dispatch/middleware/static.rb:64:in `call'
rack (1.5.2) lib/rack/sendfile.rb:112:in `call'
airbrake (3.1.14) lib/airbrake/user_informer.rb:16:in `_call'
airbrake (3.1.14) lib/airbrake/user_informer.rb:12:in `call'
railties (4.0.1) lib/rails/engine.rb:511:in `call'
railties (4.0.1) lib/rails/application.rb:97:in `call'
railties (4.0.1) lib/rails/railtie/configurable.rb:30:in `method_missing'
unicorn (4.6.3) lib/unicorn/http_server.rb:552:in `process_client'
unicorn (4.6.3) lib/unicorn/http_server.rb:632:in `worker_loop'
newrelic_rpm (3.6.7.152) lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb:22:in `call'
newrelic_rpm (3.6.7.152) lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb:22:in `block (4 levels) in <top (required)>'
unicorn (4.6.3) lib/unicorn/http_server.rb:500:in `spawn_missing_workers'
unicorn (4.6.3) lib/unicorn/http_server.rb:142:in `start'
unicorn (4.6.3) bin/unicorn_rails:209:in `<top (required)>'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bin/unicorn_rails:23:in `load'
/mnt/srv/client_portal/shared/bundle/ruby/2.0.0/bin/unicorn_rails:23:in `<main>'

Makara Gem: v0.2.0.beta6
Postgres : 9.2
Rails : 4.0.1
Ruby : 2.0.0

Thanks for your help!

error running "rails dbconsole" when using makara_mysql2 DB adapter

When using the makara_mysql2 adapter, running "rails dbconsole" (in rails v3.2+) results in the following error:

"Unknown command-line client for my_database. Submit a Rails patch to add support!"

Looking at the rails source code, if the makara adapter were named/aliased mysql2_makara, then dbconsole work work. The adapter name is not matching any of the rails expected adapter name prefixes:

See: https://github.com/rails/rails/blob/3-2-stable/railties/lib/rails/commands/dbconsole.rb

MySQL2::Error exception when running update_all

I am experiencing this MySQL2::Error with error number 0 when running update_all query.

Model.update_all(['field =?', value], ['field = ?', value])

I am getting:

rake aborted!

/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/gems/activerecord-3.2.13/lib/active_record/connection_adapters/mysql2_adapter.rb:239:in `affected_rows'
/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/gems/activerecord-3.2.13/lib/active_record/connection_adapters/mysql2_adapter.rb:239:in `exec_delete'
/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:96:in `update'
/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/query_cache.rb:14:in `update'
/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/bundler/gems/makara-05bc94ff1c6e/lib/active_record/connection_adapters/makara_adapter.rb:139:in `update'
/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/bundler/gems/makara-05bc94ff1c6e/lib/active_record/connection_adapters/makara_adapter.rb:142:in `method_missing'
/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/gems/activerecord-3.2.13/lib/active_record/relation.rb:294:in `update_all'
/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/gems/activerecord-3.2.13/lib/active_record/relation.rb:278:in `update_all'
/Users/moshebergman/.rvm/gems/ruby-1.9.3-p327@ewok/gems/activerecord-3.2.13/lib/active_record/querying.rb:7:in `update_all'

Switching to mysql2 adapter and things are working fine. So I wonder what can be the issue. This is with makara from the date "Jan 29, 2013", I will try updating to the latest version.

rspec transaction rollback errors

When running rspec, every test outputs the error:

/Users/ryanlefevre/.rvm/gems/ruby-2.0.0-p353/bundler/gems/makara-fd03ae9cee58/lib/makara/proxy.rb:81:in `block in respond_to_missing?': delegator does not forward private method #rollback_transaction_records

Environment:

  • Ruby 2.0.0
  • Rails 3.2.16
  • Rspec 2.14.1
  • database_cleaner 1.2.0

postgis adapter

Wanting to try out makara, I noticed that /lib/active_record/connection_adapters has a slew of adapters for cases where users shuffle makara and the adapter around.

However, having to use the postgis-adapted version of postgresql ( https://github.com/rgeo/activerecord-postgis-adapter ) the database.yml file will need to refer to the adapter as postgis

I expect this will lead to a failure of sorts for makara to run properly. Any thoughts on how to face this issue and possible consequences?

similar issue to #39

Rails 4.0.3 and Ruby 2.1.0 if I switch back to Ruby 2.0 or earlier it goes away. I will add more detail as I get it but wanted to let you know it's not an isolated issue.

makara installs locally but cannot deploy

Under .rvm/rubies/ruby-1.9.3-p550 for a rails3.2.18 app bundle install command executes completely with the following syntax
gem 'makara', :github => 'taskrabbit/makara', :branch => '~> 0.3.0'

However upon deployment rake aborts
rake aborted! Please install the postgresql_makara adapter:gem install activerecord-postgresql_makara-adapter(cannot load such file -- active_record/connection_adapters/postgresql_makara_adapter)
The gem install command does not run as it is not listed in rubygems.

All Connections Blacklisted

I recently upgraded to Rails 4 and have been receiving frequent ActiveRecord and Makara errors with regard to client connectivity. It appears the database client connection is unexpectedly disconnecting, causing makara to temporarily blacklist all connections. I'm using v0.2.0.

It's hard to see where/what the issue is, but here are a few traces: https://gist.github.com/justindowning/f15b9de02f9af01b63a6

Adapter does not rescue failed connection (PostgreSQL)

When trying to use the rescue_connection_failures parameter, I am expecting the adapter to slot in a database server the comes online, even if it's not available at startup.

  1. Start the application with the slave database down
  2. Request /sign_up and receive 200 OK
  3. Stop the master database
  4. Start the slave database
  5. Request /sign_up again
Started GET "/sign_up" for 10.0.2.2 at 2014-01-29 17:31:11 +0000
Processing by UsersController#new as HTML
  [master-db1] User Exists (1.9ms)  SELECT 1 AS one FROM "users" WHERE "users"."registration_ip" = '10.0.2.2' LIMIT 1
PG::ConnectionBad: PQconsumeInput() SSL connection has been closed unexpectedly
: SELECT  1 AS one FROM "users"  WHERE "users"."registration_ip" = '10.0.2.2' LIMIT 1
  Rendered users/_form.html.haml (20.2ms)
  Rendered users/new.html.haml within layouts/application (21.7ms)
Completed 500 Internal Server Error in 24ms

ActionView::Template::Error ([Makara] All connections are blacklisted - [Makara] Blacklisted connection: master-db1 -> PG::ConnectionBad: PQconsumeInput() SSL connection has been closed unexpectedly
: SELECT  1 AS one FROM "users"  WHERE "users"."registration_ip" = '10.0.2.2' LIMIT 1):
    14:   = form.error_messages
    15: 
    16: .register
    17:   %ul{ id: @user.ip_exists? ? :recaptcha : nil }
    18:     - if [email protected]_optional?
    19:       %li
    20:         = form.text_field :email, placeholder: "Email Address", id: "email"
  app/models/user/auth.rb:73:in `ip_exists?'
  app/views/users/_form.html.haml:17:in `_app_views_users__form_html_haml___1843923648617887666_70012673158620'
  app/views/users/new.html.haml:28:in `block in _app_views_users_new_html_haml___1920575446286058696_70012672998100'
  app/views/users/new.html.haml:25:in `_app_views_users_new_html_haml___1920575446286058696_70012672998100'

/bundler/gems/makara-1dea24673e5a/lib/makara/pool.rb:82 in "provide"
/bundler/gems/makara-1dea24673e5a/lib/makara/proxy.rb:82 in "block in appropriate_connection"
/bundler/gems/makara-1dea24673e5a/lib/makara/proxy.rb:123 in "appropriate_pool"
/bundler/gems/makara-1dea24673e5a/lib/makara/proxy.rb:81 in "appropriate_connection"
/bundler/gems/makara-1dea24673e5a/lib/active_record/connection_adapters/makara_abstract_adapter.rb:83 in "appropriate_connection"
/bundler/gems/makara-1dea24673e5a/lib/makara/proxy.rb:22 in "block (2 levels) in hijack_method"
(eval):45 in "block in exec_query"
(eval):14 in "_makara_hijack"
(eval):43 in "exec_query"
/gems/activerecord-4.0.2/lib/active_record/connection_adapters/postgresql_adapter.rb:891 in "select"
/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/database_statements.rb:24 in "select_all"
/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/query_cache.rb:61 in "block in select_all"
/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/query_cache.rb:76 in "cache_sql"
/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/query_cache.rb:61 in "select_all"
/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/database_statements.rb:30 in "select_one"
/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/database_statements.rb:36 in "select_value"
/bundler/gems/makara-1dea24673e5a/lib/makara/connection_wrapper.rb:39 in "method_missing"
/gems/activerecord-4.0.2/lib/active_record/relation/finder_methods.rb:174 in "exists?"
/gems/activerecord-4.0.2/lib/active_record/querying.rb:3 in "exists?"
/app/models/user/auth.rb:73 in "ip_exists?"
/app/views/users/_form.html.haml:17 in "_app_views_users__form_html_haml___1843923648617887666_70012673158620"
/gems/actionpack-4.0.2/lib/action_view/template.rb:143 in "block in render"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "block in instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications/instrumenter.rb:20 in "instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "instrument"
/gems/actionpack-4.0.2/lib/action_view/template.rb:141 in "render"
/gems/actionpack-4.0.2/lib/action_view/renderer/partial_renderer.rb:306 in "render_partial"
/gems/actionpack-4.0.2/lib/action_view/renderer/partial_renderer.rb:279 in "block in render"
/gems/actionpack-4.0.2/lib/action_view/renderer/abstract_renderer.rb:38 in "block in instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "block in instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications/instrumenter.rb:20 in "instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "instrument"
/gems/actionpack-4.0.2/lib/action_view/renderer/abstract_renderer.rb:38 in "instrument"
/gems/actionpack-4.0.2/lib/action_view/renderer/partial_renderer.rb:278 in "render"
/gems/actionpack-4.0.2/lib/action_view/renderer/renderer.rb:47 in "render_partial"
/gems/actionpack-4.0.2/lib/action_view/renderer/renderer.rb:21 in "render"
/gems/actionpack-4.0.2/lib/action_view/helpers/rendering_helper.rb:24 in "render"
/gems/haml-4.0.4/lib/haml/helpers/action_view_mods.rb:10 in "block in render_with_haml"
/gems/haml-4.0.4/lib/haml/helpers.rb:89 in "non_haml"
/gems/haml-4.0.4/lib/haml/helpers/action_view_mods.rb:10 in "render_with_haml"
/app/views/users/new.html.haml:28 in "block in _app_views_users_new_html_haml___1920575446286058696_70012672998100"
/gems/haml-4.0.4/lib/haml/helpers/action_view_mods.rb:144 in "call"
/gems/haml-4.0.4/lib/haml/helpers/action_view_mods.rb:144 in "block (2 levels) in form_for_with_haml"
/gems/haml-4.0.4/lib/haml/helpers.rb:278 in "with_tabs"
/gems/haml-4.0.4/lib/haml/helpers/action_view_mods.rb:144 in "block in form_for_with_haml"
/gems/actionpack-4.0.2/lib/action_view/helpers/capture_helper.rb:38 in "block in capture"
/gems/actionpack-4.0.2/lib/action_view/helpers/capture_helper.rb:200 in "with_output_buffer"
/gems/haml-4.0.4/lib/haml/helpers/action_view_xss_mods.rb:5 in "with_output_buffer_with_haml_xss"
/gems/actionpack-4.0.2/lib/action_view/helpers/capture_helper.rb:38 in "capture"
/gems/haml-4.0.4/lib/haml/helpers/action_view_mods.rb:59 in "capture_with_haml"
/gems/actionpack-4.0.2/lib/action_view/helpers/form_helper.rb:435 in "form_for"
/gems/haml-4.0.4/lib/haml/helpers/action_view_mods.rb:146 in "form_for_with_haml"
/gems/haml-4.0.4/lib/haml/helpers/action_view_xss_mods.rb:28 in "form_for_with_haml_xss"
/app/views/users/new.html.haml:25 in "_app_views_users_new_html_haml___1920575446286058696_70012672998100"
/gems/actionpack-4.0.2/lib/action_view/template.rb:143 in "block in render"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "block in instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications/instrumenter.rb:20 in "instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "instrument"
/gems/actionpack-4.0.2/lib/action_view/template.rb:141 in "render"
/gems/actionpack-4.0.2/lib/action_view/renderer/template_renderer.rb:49 in "block (2 levels) in render_template"
/gems/actionpack-4.0.2/lib/action_view/renderer/abstract_renderer.rb:38 in "block in instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "block in instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications/instrumenter.rb:20 in "instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "instrument"
/gems/actionpack-4.0.2/lib/action_view/renderer/abstract_renderer.rb:38 in "instrument"
/gems/actionpack-4.0.2/lib/action_view/renderer/template_renderer.rb:48 in "block in render_template"
/gems/actionpack-4.0.2/lib/action_view/renderer/template_renderer.rb:56 in "render_with_layout"
/gems/actionpack-4.0.2/lib/action_view/renderer/template_renderer.rb:47 in "render_template"
/gems/actionpack-4.0.2/lib/action_view/renderer/template_renderer.rb:17 in "render"
/gems/actionpack-4.0.2/lib/action_view/renderer/renderer.rb:42 in "render_template"
/gems/actionpack-4.0.2/lib/action_view/renderer/renderer.rb:23 in "render"
/gems/actionpack-4.0.2/lib/abstract_controller/rendering.rb:127 in "_render_template"
/gems/actionpack-4.0.2/lib/action_controller/metal/streaming.rb:219 in "_render_template"
/gems/actionpack-4.0.2/lib/abstract_controller/rendering.rb:120 in "render_to_body"
/gems/actionpack-4.0.2/lib/action_controller/metal/rendering.rb:33 in "render_to_body"
/gems/actionpack-4.0.2/lib/action_controller/metal/renderers.rb:26 in "render_to_body"
/gems/actionpack-4.0.2/lib/abstract_controller/rendering.rb:97 in "render"
/gems/actionpack-4.0.2/lib/action_controller/metal/rendering.rb:16 in "render"
/gems/actionpack-4.0.2/lib/action_controller/metal/instrumentation.rb:41 in "block (2 levels) in render"
/gems/activesupport-4.0.2/lib/active_support/core_ext/benchmark.rb:12 in "block in ms"
/usr/local/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/benchmark.rb:296 in "realtime"
/gems/activesupport-4.0.2/lib/active_support/core_ext/benchmark.rb:12 in "ms"
/gems/actionpack-4.0.2/lib/action_controller/metal/instrumentation.rb:41 in "block in render"
/gems/actionpack-4.0.2/lib/action_controller/metal/instrumentation.rb:84 in "cleanup_view_runtime"
/gems/activerecord-4.0.2/lib/active_record/railties/controller_runtime.rb:25 in "cleanup_view_runtime"
/gems/actionpack-4.0.2/lib/action_controller/metal/instrumentation.rb:40 in "render"
/gems/actionpack-4.0.2/lib/action_controller/metal/implicit_render.rb:10 in "default_render"
/gems/actionpack-4.0.2/lib/action_controller/metal/implicit_render.rb:5 in "send_action"
/gems/actionpack-4.0.2/lib/abstract_controller/base.rb:189 in "process_action"
/gems/actionpack-4.0.2/lib/action_controller/metal/rendering.rb:10 in "process_action"
/gems/actionpack-4.0.2/lib/abstract_controller/callbacks.rb:18 in "block in process_action"
/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:453 in "_run__800841590619363631__process_action__callbacks"
/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:80 in "run_callbacks"
/gems/actionpack-4.0.2/lib/abstract_controller/callbacks.rb:17 in "process_action"
/gems/actionpack-4.0.2/lib/action_controller/metal/rescue.rb:29 in "process_action"
/gems/actionpack-4.0.2/lib/action_controller/metal/instrumentation.rb:31 in "block in process_action"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "block in instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications/instrumenter.rb:20 in "instrument"
/gems/activesupport-4.0.2/lib/active_support/notifications.rb:159 in "instrument"
/gems/actionpack-4.0.2/lib/action_controller/metal/instrumentation.rb:30 in "process_action"
/gems/actionpack-4.0.2/lib/action_controller/metal/params_wrapper.rb:245 in "process_action"
/gems/activerecord-4.0.2/lib/active_record/railties/controller_runtime.rb:18 in "process_action"
/gems/actionpack-4.0.2/lib/abstract_controller/base.rb:136 in "process"
/gems/actionpack-4.0.2/lib/abstract_controller/rendering.rb:44 in "process"
/gems/actionpack-4.0.2/lib/action_controller/metal.rb:195 in "dispatch"
/gems/actionpack-4.0.2/lib/action_controller/metal/rack_delegation.rb:13 in "dispatch"
/gems/actionpack-4.0.2/lib/action_controller/metal.rb:231 in "block in action"
/gems/actionpack-4.0.2/lib/action_dispatch/routing/route_set.rb:80 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/routing/route_set.rb:80 in "dispatch"
/gems/actionpack-4.0.2/lib/action_dispatch/routing/route_set.rb:48 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/journey/router.rb:71 in "block in call"
/gems/actionpack-4.0.2/lib/action_dispatch/journey/router.rb:59 in "each"
/gems/actionpack-4.0.2/lib/action_dispatch/journey/router.rb:59 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/routing/route_set.rb:680 in "call"
/gems/rakismet-1.2.1/lib/rakismet/middleware.rb:10 in "call"
/gems/omniauth-1.1.4/lib/omniauth/strategy.rb:184 in "call!"
/gems/omniauth-1.1.4/lib/omniauth/strategy.rb:164 in "call"
/gems/omniauth-1.1.4/lib/omniauth/strategy.rb:184 in "call!"
/gems/omniauth-1.1.4/lib/omniauth/strategy.rb:164 in "call"
/gems/omniauth-1.1.4/lib/omniauth/builder.rb:49 in "call"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/rack/error_collector.rb:12 in "call"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/rack/agent_hooks.rb:18 in "call"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/rack/browser_monitoring.rb:16 in "call"
/gems/rack-recaptcha-0.6.6/lib/rack/recaptcha.rb:50 in "_call"
/gems/rack-recaptcha-0.6.6/lib/rack/recaptcha.rb:37 in "call"
/bundler/gems/makara-1dea24673e5a/lib/makara/middleware.rb:26 in "call"
/gems/rack-1.5.2/lib/rack/etag.rb:23 in "call"
/gems/rack-1.5.2/lib/rack/conditionalget.rb:25 in "call"
/gems/rack-1.5.2/lib/rack/head.rb:11 in "call"
/gems/clearance-1.1.0/lib/clearance/rack_session.rb:10 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/params_parser.rb:27 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/flash.rb:241 in "call"
/gems/rack-1.5.2/lib/rack/session/abstract/id.rb:225 in "context"
/gems/rack-1.5.2/lib/rack/session/abstract/id.rb:220 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/cookies.rb:486 in "call"
/gems/activerecord-4.0.2/lib/active_record/query_cache.rb:36 in "call"
/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:626 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/callbacks.rb:29 in "block in call"
/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:373 in "_run__4462727209502016602__call__callbacks"
/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:80 in "run_callbacks"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/callbacks.rb:27 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/remote_ip.rb:76 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/debug_exceptions.rb:17 in "call"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/show_exceptions.rb:30 in "call"
/gems/railties-4.0.2/lib/rails/rack/logger.rb:38 in "call_app"
/gems/railties-4.0.2/lib/rails/rack/logger.rb:20 in "block in call"
/gems/activesupport-4.0.2/lib/active_support/tagged_logging.rb:67 in "block in tagged"
/gems/activesupport-4.0.2/lib/active_support/tagged_logging.rb:25 in "tagged"
/gems/activesupport-4.0.2/lib/active_support/tagged_logging.rb:67 in "tagged"
/gems/railties-4.0.2/lib/rails/rack/logger.rb:20 in "call"
/gems/quiet_assets-1.0.2/lib/quiet_assets.rb:18 in "call_with_quiet_assets"
/gems/actionpack-4.0.2/lib/action_dispatch/middleware/request_id.rb:21 in "call"
/gems/rack-1.5.2/lib/rack/methodoverride.rb:21 in "call"
/gems/rack-1.5.2/lib/rack/runtime.rb:17 in "call"
/gems/rack-1.5.2/lib/rack/sendfile.rb:112 in "call"
/gems/railties-4.0.2/lib/rails/engine.rb:511 in "call"
/gems/railties-4.0.2/lib/rails/application.rb:97 in "call"
/gems/railties-4.0.2/lib/rails/railtie/configurable.rb:30 in "method_missing"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:552 in "call"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:552 in "process_client"
/gems/unicorn-4.6.2/lib/unicorn/oob_gc.rb:60 in "process_client"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:632 in "worker_loop"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:500 in "spawn_missing_workers"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:142 in "start"
/gems/unicorn-4.6.2/bin/unicorn:126 in "<top (required)>"
/usr/local/rbenv/versions/2.0.0-p195/bin/unicorn:23 in "load"
/usr/local/rbenv/versions/2.0.0-p195/bin/unicorn:23 in "<main>"

Makara::Errors::AllConnectionsBlacklisted

Issue looks like similar to #36 , but in our case we are not stopping any of our slave or master database.

Stack trace from new relic is as follows :

โ€ฆ.1/bundler/gems/makara-1ac718c7650c/lib/makara/
pool.rb: 95:in provide' โ€ฆ1/bundler/gems/makara-1ac718c7650c/lib/makara/ proxy.rb: 69:inmethod_missing'
/usr/lib/ruby/1.9.1/
monitor.rb: 211:in mon_synchronize' /usr/lib/ruby/1.9.1/ monitor.rb: 211:inmon_synchronize'
โ€ฆ_adapters/abstract/
connection_specification_changes.rb: 47:in retrieve_connection' โ€ฆ_adapters/abstract/ connection_specification_changes.rb: 29:inconnection'

What might have gone wrong in this case ?

Environment details
makara version : 'v0.2.2'
Rails version : 3.2.14
Ruby version : ruby 1.9.3p484

All connections blacklisted, even after coming back online

Similar to #32

Environment:

  • Rails 4.0.2
  • Ruby 2.0.0
  • PostgreSQL 9.2
  • Makara 1dea246

Use case:

  1. Start application with master and slave db online
  2. GET generates 200
  3. Stop slave db
  4. GET generates 200
  5. Start slave db and stop master db
  6. GET generates 500

The makara adapter doesn't appear to put the slave back into the pool when it comes back online and believes all connections are blacklisted:

ActionView::Template::Error ([Makara] All connections are blacklisted - [Makara] Blacklisted connection: master-db1 -> PG::ConnectionBad: PQconsumeInput() SSL connection has been closed unexpectedly

ActionView::Template::Error (undefined method `_makara_blacklisted?' for nil:NilClass):

Uncaught exception: cannot load such file

I cannot for the life of me get this to work. I've tried 0.3.0 rc2 and rc3. i've tried 0.2.2, but everything I try yields the same results. When I go to start the server, I get this:

Uncaught exception: cannot load such file -- .../gems/activerecord-import-0.3.1/lib/activerecord-import/active_record/adapters/makara_mysql2_adapter

ruby-1.9.3-p484
Rails 3.2.15

development:
adapter: makara_mysql2 (also tried mysql2_makara)
encoding: utf8
reconnect: true
database: ****
pool: 15
username: ****
password: ****
makara:
blacklist_duration: 5
master_ttl: 5
sticky: true
rescue_connection_failures: false
connections:
- role: master
host: localhost
- role: slave
host: localhost

Any help would be great, i've been struggling for a few days on this.

Thanks!

PG adapter for The foreman

database.yaml:
production:
adapter: postgresql_makara
database: foreman
username: foreman
password: ***
host: localhost
makara:
blacklist_duration: 5
master_ttl: 5
sticky: true

output:
[....] Restarting : foreman/usr/share/foreman/vendor/ruby/1.9.1/bundler/gems/makara-e5e9f2af855c/lib/makara/config_parser.rb:65:in all_configs': undefined methodmap' for nil:NilClass (NoMethodError)
from /usr/share/foreman/vendor/ruby/1.9.1/bundler/gems/makara-e5e9f2af855c/lib/makara/config_parser.rb:48:in master_configs' from /usr/share/foreman/vendor/ruby/1.9.1/bundler/gems/makara-e5e9f2af855c/lib/makara/proxy.rb:206:ininstantiate_connections'
from /usr/share/foreman/vendor/ruby/1.9.1/bundler/gems/makara-e5e9f2af855c/lib/makara/proxy.rb:51:in initialize' from /usr/share/foreman/vendor/ruby/1.9.1/bundler/gems/makara-e5e9f2af855c/lib/active_record/connection_adapters/makara_abstract_adapter.rb:131:ininitialize'
from /usr/share/foreman/vendor/ruby/1.9.1/bundler/gems/makara-e5e9f2af855c/lib/active_record/connection_adapters/postgresql_makara_adapter.rb:19:in new' from /usr/share/foreman/vendor/ruby/1.9.1/bundler/gems/makara-e5e9f2af855c/lib/active_record/connection_adapters/postgresql_makara_adapter.rb:19:inpostgresql_makara_connection'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:315:in new_connection' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:325:incheckout_new_connection'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:247:in block (2 levels) in checkout' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:242:inloop'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:242:in block in checkout' from /usr/lib/ruby/1.9.1/monitor.rb:211:inmon_synchronize'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:239:in checkout' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:102:inblock in connection'
from /usr/lib/ruby/1.9.1/monitor.rb:211:in mon_synchronize' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:101:inconnection'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_pool.rb:410:in retrieve_connection' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_specification.rb:171:inretrieve_connection'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/connection_adapters/abstract/connection_specification.rb:145:in connection' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/model_schema.rb:310:inclear_cache!'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activerecord-3.2.18/lib/active_record/railtie.rb:103:in block (2 levels) in <class:Railtie>' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activesupport-3.2.18/lib/active_support/callbacks.rb:418:in_run__192062860__prepare__306838575__callbacks'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activesupport-3.2.18/lib/active_support/callbacks.rb:405:in __run_callback' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activesupport-3.2.18/lib/active_support/callbacks.rb:385:in_run_prepare_callbacks'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activesupport-3.2.18/lib/active_support/callbacks.rb:81:in run_callbacks' from /usr/share/foreman/vendor/ruby/1.9.1/gems/actionpack-3.2.18/lib/action_dispatch/middleware/reloader.rb:74:inprepare!'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/actionpack-3.2.18/lib/action_dispatch/middleware/reloader.rb:48:in prepare!' from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/application/finisher.rb:47:inblock in module:Finisher'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/initializable.rb:30:in instance_exec' from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/initializable.rb:30:inrun'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/initializable.rb:55:in block in run_initializers' from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/initializable.rb:54:ineach'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/initializable.rb:54:in run_initializers' from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/application.rb:136:ininitialize!'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/railtie/configurable.rb:30:in method_missing' from /usr/share/foreman/config/environment.rb:5:in<top (required)>'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in require' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:inblock in require'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:236:in load_dependency' from /usr/share/foreman/vendor/ruby/1.9.1/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:inrequire'
from /usr/share/foreman/config.ru:3:in block in <main>' from /usr/share/foreman/vendor/ruby/1.9.1/gems/rack-1.4.5/lib/rack/builder.rb:51:ininstance_eval'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/rack-1.4.5/lib/rack/builder.rb:51:in initialize' from /usr/share/foreman/config.ru:innew'
from /usr/share/foreman/config.ru:in <main>' from /usr/share/foreman/vendor/ruby/1.9.1/gems/rack-1.4.5/lib/rack/builder.rb:40:ineval'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/rack-1.4.5/lib/rack/builder.rb:40:in parse_file' from /usr/share/foreman/vendor/ruby/1.9.1/gems/rack-1.4.5/lib/rack/server.rb:200:inapp'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/commands/server.rb:46:in app' from /usr/share/foreman/vendor/ruby/1.9.1/gems/rack-1.4.5/lib/rack/server.rb:304:inwrapped_app'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/rack-1.4.5/lib/rack/server.rb:254:in start' from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/commands/server.rb:70:instart'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/commands.rb:55:in block in <top (required)>' from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/commands.rb:50:intap'
from /usr/share/foreman/vendor/ruby/1.9.1/gems/railties-3.2.18/lib/rails/commands.rb:50:in <top (required)>' from script/rails:6:inrequire'
from script/rails:6:in `

'
failed!

Database setup on CircleCI gives RAILS_CACHE error

This always happens when trying to setup the database on CircleCI. I cannot seem to produce this locally in Mac OSX. File ordering can be different on Linux, which can cause bugs like this, but I'm having a hard time pinning down where RAILS_CACHE is originally defined.

Running:

  • Ruby 2.0.0
  • Rails 3.2.16
  • makara 0.2.0 ab0b485
ubuntu@box15:~/layervault$ RAILS_ENV=test bundle exec rake db:create db:schema:load --trace
** Invoke db:create (first_time)
** Invoke db:load_config (first_time)
** Execute db:load_config
** Invoke rails_env (first_time)
** Execute rails_env
** Execute db:create
rake aborted!
uninitialized constant RAILS_CACHE
/home/ubuntu/omnivore_server/vendor/bundle/ruby/2.0.0/gems/railties-3.2.16/lib/rails.rb:90:in `cache'
/home/ubuntu/omnivore_server/vendor/bundle/ruby/2.0.0/bundler/gems/makara-fd03ae9cee58/lib/makara/cache.rb:35:in `store'
/home/ubuntu/omnivore_server/vendor/bundle/ruby/2.0.0/bundler/gems/makara-fd03ae9cee58/lib/makara/cache.rb:23:in `write'
/home/ubuntu/omnivore_server/vendor/bundle/ruby/2.0.0/bundler/gems/makara-fd03ae9cee58/lib/makara/proxy.rb:65:in `stick_to_master!'
/home/ubuntu/omnivore_server/vendor/bundle/ruby/2.0.0/bundler/gems/makara-fd03ae9cee58/lib/makara/proxy.rb:179:in `stick_to_master'

Rubygems

When will makara be uploaded as a gem on rubygems.org

Cannot load such file -- active_record/connection_adapters/mysql2_makara_adapter

I am trying to use makara with a mysql. When I add the config to database.yml:

development:
  adapter: mysql2_makara
  encoding: utf8
  database: db
  username: root
  password:
  makara:
    connections:
      - role: master
        host: 192.168.56.11

I get the following error:

2.1.0 ~/Code/ $ rails s
=> Booting Thin
=> Rails 3.2.19 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
Exiting
/Users/jrdi/.rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/activesupport-3.2.19/lib/active_support/dependencies.rb:251:in `require': Please install the mysql2_makara adapter: `gem install activerecord-mysql2_makara-adapter` (cannot load such file -- active_record/connection_adapters/mysql2_makara_adapter) (LoadError)

I am using v.0.2.2. Rails 3.2.19 & Ruby 2.1.0

Dealing with SET Edge cases

As README states: The only edge case is SET operations which are sent to all connections. Devise controller is using SET and thus leading to an error which one would like to avoid:
PG::ReadOnlySqlTransaction: ERROR: cannot execute UPDATE in a read-only transaction : UPDATE "users" SET "last_sign_in_at" = '2014-12-09 19:58:58.290982', [...]
notwithstanding the creation of an sql_proxy.rb initializer that should only handle select on the slave, as follows:

class MakaraSqlProxy < ::Makara::Proxy
  def connection_for(config)
    ::Sql::Client.new(config)
  end

  hijack_method :select, :ping
  send_to_all :connect, :reconnect, :disconnect, :clear_cache

  def needs_master?(method_name, args)
    return false if args.empty?
    sql = args.first
    sql !~ /^select/i
  end

end

Migrations are not properly working in rails 4.

Whenever I run rake db:rollback, down migration are not running.
I am using ruby2.1.2 and rails 4.1.1

I am using following config as well

development:
  adapter: makara_mysql2
  encoding: utf8
  database: mydb
  pool: 5
  username: root
  password: password
  host: localhost
  makara:
    # the following are default values
    blacklist_duration: 30
    master_ttl: 5
    sticky: true
    rescue_connection_failures: true
    connections:
      - role: master
        host: localhost
      - host: 192.168.1.2
        username: remoteuser
        password: password

Ruby 2.0 always returns nil

As part of deploying an HTTP service that depends on makara, we've discovered that Makara is not compatible with Ruby 2.0. On Ruby 2.0 (unlike on Ruby 1.9.3), all invocations of the #execute method return nil. The Makara test suite passes on Ruby 2.0 with no problems, but it fails to test for this particular issue.

When running the Makara test suite against Postgres on 1.9.3 and 2.0, I was able to reliably reproduce this issue โ€” on 1.9.3, Makara executed SQL queries against the database, and on 2.0.0, Makara did not execute the SQL query, and simply returned nil without raising an error.

Option to read from master by default

Hey, we use a fork of Makara that reads from master by default and replicas when explicitly called. We use this branch and the distribute_reads method below:

module DistributeReads
  def distribute_reads
    Thread.current[:distribute_reads] = true
    Makara::Context.set_current(Makara::Context.generate)
    yield
  ensure
    Thread.current[:distribute_reads] = false
  end
end

Object.send :include, DistributeReads

which allows you to do:

distribute_reads { User.count }

What are your thoughts on supporting a similar option or pattern out of the box?

using multiple top-level configs with maraka, is this supported/workaround?

hi

we are using makara and it works great, when we have one DB configuration but we have some apps that use multiple top level configurations. e.g.

development:
adapter: makara
db_adapter: mysql2
host: production_read_only
//// other fields left out for brevity
databases:

  • name: master
    role: master
    host: production_read_write
  • name: slave
    role: slave
    host: production_read_only
    marketing_development:
    adapter: makara
    db_adapter: mysql2
    host: marketing_read_only
    //// other fields left out for brevity
    databases:
  • name: master
    role: master
    host: marketing_read_write
  • name: slave
    role: slave
    host: marketing_read_only

We have some isolated models that switch between connections using the standard 'establish_connection' usage. Example:

class User < ActiveRecord::Base <- Always uses development makara config
end

class MarketingSomething < ActiveRecord::Base
establish_connection("marketing_#{Rails.env}") <- For example
end

This works fine and dandy when using the mysql2 gem. However what happens when using makara is that it starts off using the correct makara adapter (marketing_development) but then finally falls back to the 'developent' makara adapter for which then breaks the queries. Ultimatly I figured out the following line of code

../decorator.rb
adapter = Makara.connection <--------
if adapter && !adapter.hijacking?

makara.rb
def connection
return nil unless ActiveRecord::Base.connection.respond_to?(:unstick!)
ActiveRecord::Base.connection
end

Ultimately the Makara.connection will always return the 'development' connection based on the above line.

We have been trying a wide number of ways over the last few days to overcome this and to stash 'last known makara adapter' be it in thread current variables or similar to no avail.

I was wondering if anybody using makara and reading this have had such situations. We are in the process of 'one database/cluster per logical application' but right now we do connect to multiples.

any help is appreciated in advance.

support multiple databases

I am starting to use Makara - I am having no issues connecting to my pg master / dual pg slave on my main app's database.

However, we, like many other apps out there rely on multiple databases, our app servers from our main database and our workers consume data from a vendor database using establish_connection on AR models as such:

class VendorDataModel < ActiveRecord::Base
  establish_connection "#{Rails.env}_vendor_data"
end

It looks like this call no longer has any effect (Rails 4.1.8)

VendorDataModel.establish_connection
VendorDataModel.first # will result in an error, no such relation...

I'm about to dive into the code, but perhaps someone can let me know - is this supported and undocumented, if it isn't supported would you accept a patch?

Manually running:

connection = ActiveRecord::Base.establish_connection(...YAML...)[Rails.env]

Appears to work fine however.

Can anyone provide some insight?

Connect manually

I'm trying to generate a custom database.yml on the fly but I always get a RuntimeError: [Makara] You must include at least one connection that serves as a master exception.

This is my hash:

{
        :adapter => "makara",
     :db_adapter => "abstract",
    :connections => [
        [0] {
             :adapter => "makara_postgresql",
                :host => "localhost",
            :username => "root",
            :password => nil,
            :database => "novo_exemplo_development",
                :port => nil,
                :name => "master",
                :role => "master"
        }
    ]
}

And to connect:

ActiveRecord::Base.establish_connection(database_hash)

What am I doing wrong?

add redis as centralised cache store

I am planning to use makara gem for rails application. I want to use redis as my cache store that will be shared between multiple server running the application.

the commands supported by makara cache are read and write. How can we add support for redis.

Performance regression when upgrading to v0.2.2

Hello! We are big fans of Makara at Storehouse. Yesterday we tried to update to v0.2.2 (we were on 362fe9f). The specific SHA we deployed was 1ac718c7. Unfortunately it caused a big performance regression for us and we had to rollback. To give you an idea, this is our newrelic from yesterday:

screen shot 2014-05-21 at 10 30 24 am

If we can be helpful in any way, please let us know. Sorry that I don't have more details to offer.

Brian

Redis not reconnecting

We are using unicorn and have noticed that using makara does not reconnect to redis properly any more when the application is restarted.

Relevant unicorn.rb snippet:

after_fork do |server,worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection

Error:
Redis::InheritedError: Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.

Backtrace:

/gems/redis-3.0.6/lib/redis/client.rb:287 in "ensure_connected"
/gems/redis-3.0.6/lib/redis/client.rb:179 in "block in process"
/gems/redis-3.0.6/lib/redis/client.rb:258 in "logging"
/gems/redis-3.0.6/lib/redis/client.rb:178 in "process"
/gems/redis-3.0.6/lib/redis/client.rb:84 in "call"
/gems/newrelic-redis-1.4.0/lib/newrelic_redis/instrumentation.rb:41 in "block in call_with_newrelic_trace"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/agent/method_tracer.rb:273 in "trace_execution_scoped"
/gems/newrelic-redis-1.4.0/lib/newrelic_redis/instrumentation.rb:37 in "call_with_newrelic_trace"
/gems/redis-3.0.6/lib/redis.rb:690 in "block in setex"
/gems/redis-3.0.6/lib/redis.rb:36 in "block in synchronize"
/usr/local/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/monitor.rb:211 in "mon_synchronize"
/gems/redis-3.0.6/lib/redis.rb:36 in "synchronize"
/gems/redis-3.0.6/lib/redis.rb:689 in "setex"
/gems/redis-store-1.1.2/lib/redis/store/interface.rb:17 in "setex"
/gems/redis-store-1.1.2/lib/redis/store/marshalling.rb:13 in "block in setex"
/gems/redis-store-1.1.2/lib/redis/store/marshalling.rb:29 in "_marshal"
/gems/redis-store-1.1.2/lib/redis/store/marshalling.rb:13 in "setex"
/gems/redis-store-1.1.2/lib/redis/store/ttl.rb:6 in "set"
/gems/redis-store-1.1.2/lib/redis/store/marshalling.rb:5 in "block in set"
/gems/redis-store-1.1.2/lib/redis/store/marshalling.rb:29 in "_marshal"
/gems/redis-store-1.1.2/lib/redis/store/marshalling.rb:5 in "set"
/gems/redis-store-1.1.2/lib/redis/store/namespace.rb:5 in "block in set"
/gems/redis-store-1.1.2/lib/redis/store/namespace.rb:50 in "namespace"
/gems/redis-store-1.1.2/lib/redis/store/namespace.rb:5 in "set"
/gems/redis-activesupport-3.2.3/lib/active_support/cache/redis_store.rb:145 in "write_entry"
/gems/redis-activesupport-3.2.3/lib/active_support/cache/redis_store.rb:35 in "block in write"
/gems/activesupport-3.2.16/lib/active_support/cache.rb:520 in "instrument"
/gems/redis-activesupport-3.2.3/lib/active_support/cache/redis_store.rb:33 in "write"
/gems/activesupport-3.2.16/lib/active_support/core_ext/object/try.rb:36 in "try"
/bundler/gems/makara-1421901ef8d1/lib/makara/cache.rb:23 in "write"
/bundler/gems/makara-1421901ef8d1/lib/makara/proxy.rb:65 in "stick_to_master!"
/bundler/gems/makara-1421901ef8d1/lib/makara/proxy.rb:179 in "stick_to_master"
/bundler/gems/makara-1421901ef8d1/lib/makara/proxy.rb:116 in "appropriate_pool"
/bundler/gems/makara-1421901ef8d1/lib/makara/proxy.rb:100 in "appropriate_connection"
/bundler/gems/makara-1421901ef8d1/lib/active_record/connection_adapters/makara_abstract_adapter.rb:93 in "appropriate_connection"
/bundler/gems/makara-1421901ef8d1/lib/makara/proxy.rb:22 in "block (2 levels) in hijack_method"
(eval):49 in "block in exec_query"
(eval):17 in "_makara_hijack"
(eval):47 in "exec_query"
/gems/activerecord-3.2.16/lib/active_record/connection_adapters/postgresql_adapter.rb:794 in "table_exists?"
/gems/activerecord-3.2.16/lib/active_record/connection_adapters/schema_cache.rb:30 in "table_exists?"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:92 in "table_exists?"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:99 in "column_for"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:430 in "visit_Arel_Attributes_Attribute"
/gems/arel-3.0.3/lib/arel/visitors/visitor.rb:19 in "visit"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:134 in "block in visit_Arel_Nodes_SelectCore"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:134 in "map"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:134 in "visit_Arel_Nodes_SelectCore"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:121 in "block in visit_Arel_Nodes_SelectStatement"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:121 in "map"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:121 in "visit_Arel_Nodes_SelectStatement"
/gems/arel-3.0.3/lib/arel/visitors/visitor.rb:19 in "visit"
/gems/arel-3.0.3/lib/arel/visitors/visitor.rb:5 in "accept"
/gems/arel-3.0.3/lib/arel/visitors/to_sql.rb:19 in "accept"
/gems/activerecord-3.2.16/lib/active_record/connection_adapters/abstract/database_statements.rb:7 in "to_sql"
/gems/activerecord-3.2.16/lib/active_record/connection_adapters/abstract/query_cache.rb:60 in "select_all"
/bundler/gems/makara-1421901ef8d1/lib/makara/connection_wrapper.rb:82 in "method_missing"
/bundler/gems/makara-1421901ef8d1/lib/makara/proxy.rb:71 in "block in method_missing"
/bundler/gems/makara-1421901ef8d1/lib/makara/pool.rb:83 in "block in provide"
/bundler/gems/makara-1421901ef8d1/lib/active_record/connection_adapters/makara_abstract_adapter.rb:13 in "handle"
/bundler/gems/makara-1421901ef8d1/lib/makara/pool.rb:82 in "provide"
/bundler/gems/makara-1421901ef8d1/lib/makara/proxy.rb:69 in "method_missing"
/gems/activerecord-3.2.16/lib/active_record/querying.rb:38 in "block in find_by_sql"
/gems/activerecord-3.2.16/lib/active_record/explain.rb:41 in "logging_query_plan"
/gems/activerecord-3.2.16/lib/active_record/querying.rb:37 in "find_by_sql"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/agent/method_tracer.rb:523 in "block in find_by_sql_with_trace_ActiveRecord_self_name_find_by_sql"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/agent/method_tracer.rb:273 in "trace_execution_scoped"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/agent/method_tracer.rb:518 in "find_by_sql_with_trace_ActiveRecord_self_name_find_by_sql"
/gems/activerecord-3.2.16/lib/active_record/relation.rb:171 in "exec_queries"
/gems/activerecord-3.2.16/lib/active_record/relation.rb:160 in "block in to_a"
/gems/activerecord-3.2.16/lib/active_record/explain.rb:41 in "logging_query_plan"
/gems/activerecord-3.2.16/lib/active_record/relation.rb:159 in "to_a"
/gems/activerecord-3.2.16/lib/active_record/relation/finder_methods.rb:381 in "find_first"
/gems/activerecord-3.2.16/lib/active_record/relation/finder_methods.rb:122 in "first"
/gems/activerecord-3.2.16/lib/active_record/relation/finder_methods.rb:267 in "find_by_attributes"
/gems/activerecord-3.2.16/lib/active_record/dynamic_matchers.rb:50 in "method_missing"
/config/routes.rb:44 in "matches?"
/gems/actionpack-3.2.16/lib/action_dispatch/routing/mapper.rb:30 in "block in matches?"
/gems/actionpack-3.2.16/lib/action_dispatch/routing/mapper.rb:29 in "each"
/gems/actionpack-3.2.16/lib/action_dispatch/routing/mapper.rb:29 in "matches?"
/gems/actionpack-3.2.16/lib/action_dispatch/routing/mapper.rb:43 in "call"
/gems/journey-1.0.4/lib/journey/router.rb:68 in "block in call"
/gems/journey-1.0.4/lib/journey/router.rb:56 in "each"
/gems/journey-1.0.4/lib/journey/router.rb:56 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/routing/route_set.rb:608 in "call"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/rack/error_collector.rb:12 in "call"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/rack/agent_hooks.rb:18 in "call"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/rack/browser_monitoring.rb:16 in "call"
/gems/sass-3.2.12/lib/sass/plugin/rack.rb:54 in "call"
/bundler/gems/makara-1421901ef8d1/lib/makara/middleware.rb:26 in "call"
/gems/warden-1.2.1/lib/warden/manager.rb:35 in "block in call"
/gems/warden-1.2.1/lib/warden/manager.rb:34 in "catch"
/gems/warden-1.2.1/lib/warden/manager.rb:34 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/best_standards_support.rb:17 in "call"
/gems/rack-1.4.5/lib/rack/etag.rb:23 in "call"
/gems/rack-1.4.5/lib/rack/conditionalget.rb:25 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/head.rb:14 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/params_parser.rb:21 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/flash.rb:242 in "call"
/gems/rack-1.4.5/lib/rack/session/abstract/id.rb:210 in "context"
/gems/rack-1.4.5/lib/rack/session/abstract/id.rb:205 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/cookies.rb:341 in "call"
/gems/activerecord-3.2.16/lib/active_record/query_cache.rb:64 in "call"
/gems/activerecord-3.2.16/lib/active_record/connection_adapters/abstract/connection_pool.rb:479 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/callbacks.rb:28 in "block in call"
/gems/activesupport-3.2.16/lib/active_support/callbacks.rb:405 in "_run__815282141766907249__call__2348151881767625911__callbacks"
/gems/activesupport-3.2.16/lib/active_support/callbacks.rb:405 in "__run_callback"
/gems/activesupport-3.2.16/lib/active_support/callbacks.rb:385 in "_run_call_callbacks"
/gems/activesupport-3.2.16/lib/active_support/callbacks.rb:81 in "run_callbacks"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/callbacks.rb:27 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/remote_ip.rb:31 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/debug_exceptions.rb:16 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/show_exceptions.rb:56 in "call"
/gems/railties-3.2.16/lib/rails/rack/logger.rb:32 in "call_app"
/gems/railties-3.2.16/lib/rails/rack/logger.rb:16 in "block in call"
/gems/activesupport-3.2.16/lib/active_support/tagged_logging.rb:22 in "tagged"
/gems/railties-3.2.16/lib/rails/rack/logger.rb:16 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/request_id.rb:22 in "call"
/gems/rack-1.4.5/lib/rack/methodoverride.rb:21 in "call"
/gems/rack-1.4.5/lib/rack/runtime.rb:17 in "call"
/gems/rack-1.4.5/lib/rack/lock.rb:15 in "call"
/gems/actionpack-3.2.16/lib/action_dispatch/middleware/static.rb:63 in "call"
/gems/railties-3.2.16/lib/rails/engine.rb:484 in "call"
/gems/railties-3.2.16/lib/rails/application.rb:231 in "call"
/gems/railties-3.2.16/lib/rails/railtie/configurable.rb:30 in "method_missing"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:552 in "call"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:552 in "process_client"
/gems/unicorn-4.6.2/lib/unicorn/oob_gc.rb:60 in "process_client"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:632 in "worker_loop"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb:22 in "call"
/gems/newrelic_rpm-3.6.1.88/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb:22 in "block (4 levels) in <top (required)>"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:500 in "spawn_missing_workers"
/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:142 in "start"
/gems/unicorn-4.6.2/bin/unicorn:126 in "<top (required)>"
/bin/unicorn:23 in "load"
/bin/unicorn:23 in "<main>"

SELECTs not going to slave

Hello,

99% of my SELECTs are going to master. It is strange because there are a couple requests going to slave, but it's VERY rare. It seems like requests made to front end pages (an admin portal) go to slaves, but anything hitting our API (where all the traffic comes from) goes to master no matter what.

We are using Amazon RDS and the slave has had 100% uptime always. My config looks like this:

production: &production
  adapter: 'makara_mysql2'
  encoding: utf8
  database: 'mydbname'
  pool: 25
  timeout: 5000
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  port: 3306

  makara:
    blacklist_duration: 5
    master_ttl: 5
    sticky: true
    rescue_connection_failures: false

    connections:
      - role: master
        host: <%= ENV['DB_MASTER_HOST'] %>
      - role: slave
        host: <%= ENV['DB_SLAVE1_HOST'] %>

staging:
  <<: *production

I'm using Makara 0.2.2, Rails 4.1. Any thoughts?

Rails 4 Compatible?

I am having some performance issues with using the makara gem with Rails 4. After upgrading an application and generating some requests, I notice the response time is much slower. I updated the database.yml to use the postgresql adapter instead of the makara-postgresql adapter and normal response times resumed. For example:

With makara-postgresql: X-Runtime: 4.144442
WIth postgresql: X-Runtime: 0.755197

I have looked at several different reasons why this could happen, and changing the adapter seems to be the cause here. We do have another application that uses Rails 4 and the makara-postgresql adapter with no known performance reduction. I see that you have compatibility for Active Record 4 (https://github.com/taskrabbit/makara/blob/master/lib/active_record/connection_adapters/makara_postgresql_adapter.rb#L4), though neither the README or the Task Rabbit blog post indicate Rails 4 compatibility.

Any ideas why one application would be adversely affected by the use of the adapter using Rails 4?

release_master

Hello!

In a version there has been the release_master! function to release the master stuck after some circumstances.

This method has gone in latest beta 0.2.0.beta3.

Is there a possibilty to easy release the master after some inserts/updates? Because when updating some status-fields, which are not application-critical when they are inconsistent within one request, it would be nice to return to slave usage on selects.

I found the possibility to override the should_stick? method. But then I have to put all cases in there, which isn't pretty. f.e:

return false if sql.to_s =~ /my_status_field/

Any hints?

postgres issuing request to master for every query

It seems with the postgres adapter that every single request generates a SELECT 1 query to master which increases the latency greatly on my app since the master is across the internet. This is because it calls ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::active? which does a SELECT 1 to check whether the connection is alive. Is there any know workaround for this? Monkey patching that method to just return true resolves the issue in development, but not sure that's such a good solution.

Adapter not failing over when db server unavailable (PostgreSQL)

First, @mnelson nice work on this adapter!

Similar to #27 I am using PostgreSQL 9.2 with a master and slave database server. The issue I'm running into is testing the adapter's ability to switch to the master when the slave becomes unavailable.

From the README:

If all slave nodes are blacklisted, the master connection will begin receiving read queries as if it were a slave.

The scenario I'm testing is starting the application with both database servers available:

  1. Request /sign_up
  2. Stop the slave database server
  3. Refresh /sign_up
Started GET "/sign_up" for 10.0.2.2 at 2014-01-29 16:18:00 +0000
Processing by UsersController#new as HTML
  [slave-db2] User Exists (1.0ms)  SELECT 1 AS one FROM "users" WHERE "users"."registration_ip" = '10.0.2.2' LIMIT 1
PG::ConnectionBad: PQconsumeInput() SSL connection has been closed unexpectedly
: SELECT  1 AS one FROM "users"  WHERE "users"."registration_ip" = '10.0.2.2' LIMIT 1
  Rendered users/_form.html.haml (10.1ms)
  Rendered users/new.html.haml within layouts/application (11.9ms)
Completed 500 Internal Server Error in 16ms

ActionView::Template::Error (PG::ConnectionBad: PQconsumeInput() SSL connection has been closed unexpectedly
: SELECT  1 AS one FROM "users"  WHERE "users"."registration_ip" = '10.0.2.2' LIMIT 1):
    14:   = form.error_messages
    15: 
    16: .register
    17:   %ul{ id: @user.ip_exists? ? :recaptcha : nil }
    18:     - if [email protected]_optional?
    19:       %li
    20:         = form.text_field :email, placeholder: "Email Address", id: "email"
  app/models/user/auth.rb:73:in `ip_exists?'
  app/views/users/_form.html.haml:17:in `_app_views_users__form_html_haml___4520667989552407035_70094826645900'
  app/views/users/new.html.haml:28:in `block in _app_views_users_new_html_haml__3771270572460248575_70094827057120'
  app/views/users/new.html.haml:25:in `_app_views_users_new_html_haml__3771270572460248575_70094827057120'

After I start the slave database server again, the query works okay:

Started GET "/sign_up" for 10.0.2.2 at 2014-01-29 16:18:52 +0000
  [master-db1] SCHEMA (0.8ms)  SET client_min_messages TO 'warning'
  [slave-db2] SCHEMA (0.8ms)  SET client_min_messages TO 'warning'
  [slave-db2] SCHEMA (0.7ms)  SHOW client_min_messages
  [master-db1] SCHEMA (0.8ms)  SET client_min_messages TO 'panic'
  [slave-db2] SCHEMA (0.8ms)  SET client_min_messages TO 'panic'
  [master-db1] SCHEMA (0.7ms)  SET standard_conforming_strings = on
  [slave-db2] SCHEMA (0.6ms)  SET standard_conforming_strings = on
  [master-db1] SCHEMA (0.5ms)  SET client_min_messages TO 'warning'
  [slave-db2] SCHEMA (0.6ms)  SET client_min_messages TO 'warning'
  [master-db1] SCHEMA (0.6ms)  SET time zone 'UTC'
  [slave-db2] SCHEMA (0.6ms)  SET time zone 'UTC'
Processing by UsersController#new as HTML
  [slave-db2] User Exists (2.9ms)  SELECT 1 AS one FROM "users" WHERE "users"."registration_ip" = '10.0.2.2' LIMIT 1
  [master-db1] CACHE (0.0ms)  SELECT 1 AS one FROM "users" WHERE "users"."registration_ip" = '10.0.2.2' LIMIT 1
  Rendered users/_form.html.haml (12.0ms)
  Rendered users/new.html.haml within layouts/application (14.5ms)
  Rendered layouts/_legacy_ie_styles.html.erb (0.3ms)
  Rendered layouts/_at_channels_nav.html.erb (0.2ms)
  Rendered layouts/_site_bar.html.haml (1.4ms)
  Rendered layouts/_navigation.html.haml (1.0ms)
  Rendered shared/_flash_messages.html.haml (0.2ms)
  Rendered layouts/_analytics_in_body.html.erb (0.2ms)
Completed 200 OK in 50ms (Views: 45.7ms | ActiveRecord: 3.0ms)

Here is my database.yml:

production:
  database: community_production
  adapter:  makara_postgresql
  username: ******
  password: ******
  encoding: unicode
  makara:
    blacklist_duration: 5
    master_ttl: 5
    sticky: true
    rescue_connection_failures: true

    connections:
      - role: master
        host: db1
        name: master-db1
      - role: slave
        host: db2
        name: slave-db2

One other issue is the rescue_connection_failures parameter.

  1. Start the application with the slave database down
  2. Request /sign_up and receive 200 OK
  3. Stop the master database
  4. Start the slave database
  5. Request /sign_up again
Started GET "/sign_up" for 10.0.2.2 at 2014-01-29 16:15:02 +0000
Processing by UsersController#new as HTML
  Rendered users/_form.html.haml (4.2ms)
  Rendered users/new.html.haml within layouts/application (5.6ms)
Completed 500 Internal Server Error in 8ms

ActionView::Template::Error (undefined method `_makara_blacklisted?' for nil:NilClass):
    14:   = form.error_messages
    15: 
    16: .register
    17:   %ul{ id: @user.ip_exists? ? :recaptcha : nil }
    18:     - if [email protected]_optional?
    19:       %li
    20:         = form.text_field :email, placeholder: "Email Address", id: "email"
  app/models/user/auth.rb:73:in `ip_exists?'
  app/views/users/_form.html.haml:17:in `_app_views_users__form_html_haml__606789934656786232_70264339597080'
  app/views/users/new.html.haml:28:in `block in _app_views_users_new_html_haml___3704897839609099056_70264339940800'
  app/views/users/new.html.haml:25:in `_app_views_users_new_html_haml___3704897839609099056_70264339940800'

Let me know if you need more data, testing. Thanks!

Stack level too deep error

I'm trying to upgrade an existing rails project that requires master / slave replication and thread safety from DbCharmer to Makara.

This app runs a small script that automatically generates / prunes some required css files when it is starting up.

It needs to perform a select query during this script, so I have followed guides such as this http://exposinggotchas.blogspot.ca/2011/02/activerecord-migrations-without-rails.html to use ActiveRecord outside of rails.

Whenever I use ActiveRecord::Base.establish_connection to either a mysql2 adapter or a mysql2_makara adapter, I get this crash.

$ rails s
=> Booting Thin
=> Rails 3.2.16 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
Exiting
/Users/user/.rvm/gems/ruby-2.1.0/gems/rack-1.4.5/lib/rack/builder.rb:40: stack level too deep (SystemStackError)

The code that is being used

config/application.rb

    db_config = YAML::load(File.open("#{Rails.root}/config/database.yml"))[ENV["RAILS_ENV"]]['myawesomedb']
    db_config['adapter'] = 'mysql2'
    ActiveRecord::Base.establish_connection(db_config) 
    somedata = ActiveRecord::Base.connection.execute("SELECT value FROM variables WHERE name='somevariablekey'").first[0]
    ActiveRecord::Base.clear_all_connections!
    ActiveRecord::Base.clear_cache!

This error is giving me minimal information to debug with, so I'm wondering if it is a bug, or am I missing something? Should I call this task from the command line as a separate rake task, or is there some way to reset ActiveRecord after using it in this method?

I'm using Rails 3.2.16, Ruby 2.1.0, and an otherwise fairly basic gemset with no other database / activerecord stuff other than makara.

Unicorn and lazy loaded connection pool?

Not an issue, just a quick question!

We're interested in checking out makara. How does this work with the typical unicorn/rails setup where connections to the master are established at time of fork.

In order to scale out reads, ideally this connection to the master is lazy loaded or these initial connections are only to a pool of slaves? Does makara address this? Thanks!

performance issue

there seems to be pretty heavy performance issue (~3x difference)

without makara:

$ http_load -parallel 30 -seconds 30 urls.txt 
5238 fetches, 30 max parallel, 2.55437e+07 bytes, in 30 seconds
4876.62 mean bytes/connection
174.6 fetches/sec, 851458 bytes/sec
msecs/connect: 0.0776838 mean, 3.995 max, 0.03 min
msecs/first-response: 170.548 mean, 3399.14 max, 28.019 min
HTTP response codes:
  code 200 -- 5238

with makara:

$ http_load -parallel 30 -seconds 30 urls.txt 
1387 fetches, 30 max parallel, 6.79761e+06 bytes, in 30 seconds
4900.95 mean bytes/connection
46.2333 fetches/sec, 226587 bytes/sec
msecs/connect: 0.100772 mean, 4.028 max, 0.034 min
msecs/first-response: 641.824 mean, 5868.17 max, 119.309 min
HTTP response codes:
  code 200 -- 1387

my set of relevant gems are:

cat Gemfile.lock | egrep 'grape|newrelic|unicorn|makara' | grep '(' | grep -v '~'
    grape (0.10.2)
    grape-entity (0.4.4)
    makara (0.3.0.rc3)
    newrelic-grape (1.4.1)
    newrelic_rpm (3.8.1.221)
    unicorn (4.8.3)

with stackprof I found that a lot of the time/CPU spent on Delegator#method_missing

$ stackprof tmp/stackprof-cpu-12824-1422006619.dump --limit 10
==================================
  Mode: cpu(1000)
  Samples: 108 (5.26% miss rate)
  GC: 13 (12.04%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
       205 (189.8%)          35  (32.4%)     Delegator#method_missing
        10   (9.3%)          10   (9.3%)     block in Delegator#method_missing
         3   (2.8%)           3   (2.8%)     ActiveRecord::AttributeMethods::Dirty#original_raw_attributes
         2   (1.9%)           2   (1.9%)     ActiveRecord::AttributeMethods::ClassMethods#method_defined_within?
         2   (1.9%)           2   (1.9%)     ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#configure_connection
        10   (9.3%)           2   (1.9%)     ActiveModel::AttributeMethods::ClassMethods#define_proxy_call
         2   (1.9%)           2   (1.9%)     #<Module:0x007f90b7ec98d0>.mechanism
         2   (1.9%)           2   (1.9%)     block in ActiveSupport::Dependencies::Loadable#require
         1   (0.9%)           1   (0.9%)     ActiveRecord::AttributeMethods#clone_attribute_value
         1   (0.9%)           1   (0.9%)     Set#include?
$ stackprof tmp/stackprof-cpu-12824-1422006619.dump --method 'Delegator#method_missing'
Delegator#method_missing (/home/forresty/.rbenv/versions/2.1.5/lib/ruby/2.1.0/delegate.rb:76)
  samples:    35 self (32.4%)  /    205 total (189.8%)
  callers:
     123  (   60.0%)  Makara::ConnectionWrapper#method_missing
      82  (   40.0%)  block in Makara::Proxy#method_missing
  callees (170 total):
      73  (   42.9%)  Makara::ConnectionWrapper#method_missing
      26  (   15.3%)  #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0x007f90bb66e3d0>.execute
      24  (   14.1%)  #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0x007f90bb62db78>.exec_query
      21  (   12.4%)  ActiveRecord::ConnectionAdapters::QueryCache#select_all
      10  (    5.9%)  block in Delegator#method_missing
       9  (    5.3%)  Makara::Proxy#method_missing
       4  (    2.4%)  ActiveRecord::ConnectionAdapters::DatabaseStatements#select_value
       2  (    1.2%)  ensure in Delegator#method_missing
       1  (    0.6%)  ActiveRecord::ConnectionAdapters::DatabaseStatements#cacheable_query
  code:
                                  |    76  |   def method_missing(m, *args, &block)
                                  |    77  |     r = true
                                  |    78  |     target = self.__getobj__ {r = false}
                                  |    79  |     begin
    1    (0.9%) /     1   (0.9%)  |    80  |       if r && target.respond_to?(m)
  192  (177.8%) /    34  (31.5%)  |    81  |         target.__send__(m, *args, &block)
                                  |    82  |       elsif ::Kernel.respond_to?(m, true)
                                  |    83  |         ::Kernel.instance_method(m).bind(self).(*args, &block)
                                  |    84  |       else
                                  |    85  |         super(m, *args, &block)
                                  |    86  |       end
                                  |    87  |     ensure
   12   (11.1%)                   |    88  |       $@.delete_if {|t| %r"\A#{Regexp.quote(__FILE__)}:(?:#{[__LINE__-7, __LINE__-5, __LINE__-3].join('|')}):"o =~ t} if $@
                                  |    89  |     end
block in Delegator#method_missing (/home/forresty/.rbenv/versions/2.1.5/lib/ruby/2.1.0/delegate.rb:88)
  samples:    10 self (9.3%)  /     10 total (9.3%)
  callers:
      10  (  100.0%)  Delegator#method_missing
  code:
   10    (9.3%) /    10   (9.3%)  |    88  |       $@.delete_if {|t| %r"\A#{Regexp.quote(__FILE__)}:(?:#{[__LINE__-7, __LINE__-5, __LINE__-3].join('|')}):"o =~ t} if $@
                                  |    89  |     end
ensure in Delegator#method_missing (/home/forresty/.rbenv/versions/2.1.5/lib/ruby/2.1.0/delegate.rb:79)
  samples:     1 self (0.9%)  /      2 total (1.9%)
  callers:
       2  (  100.0%)  Delegator#method_missing
  callees (1 total):
       1  (  100.0%)  block in Delegator#method_missing
  code:
                                  |    79  |     begin
                                  |    80  |       if r && target.respond_to?(m)
                                  |    81  |         target.__send__(m, *args, &block)
                                  |    82  |       elsif ::Kernel.respond_to?(m, true)
                                  |    83  |         ::Kernel.instance_method(m).bind(self).(*args, &block)
                                  |    84  |       else
                                  |    85  |         super(m, *args, &block)
                                  |    86  |       end
                                  |    87  |     ensure
    2    (1.9%) /     1   (0.9%)  |    88  |       $@.delete_if {|t| %r"\A#{Regexp.quote(__FILE__)}:(?:#{[__LINE__-7, __LINE__-5, __LINE__-3].join('|')}):"o =~ t} if $@
                                  |    89  |     end
block in Delegator#method_missing (/home/forresty/.rbenv/versions/2.1.5/lib/ruby/2.1.0/delegate.rb:88)
  samples:     1 self (0.9%)  /      1 total (0.9%)
  callers:
       1  (  100.0%)  ensure in Delegator#method_missing
  code:
    1    (0.9%) /     1   (0.9%)  |    88  |       $@.delete_if {|t| %r"\A#{Regexp.quote(__FILE__)}:(?:#{[__LINE__-7, __LINE__-5, __LINE__-3].join('|')}):"o =~ t} if $@
                                  |    89  |     end

Any ideas?

Official Thinking Sphinx support

Any chance to get full support for thinking sphinx? I'm using this ugly hack to make it partially work. Btw, currently using thinking-sphinx gem locked on 2.0.14 version.

module Makara
  class << self
    def register_adapter(adapter)
      @adapters ||= []
      @adapters << adapter unless @adapters.map(&:id).include?(adapter.id)
      @adapters = @adapters.sort_by(&:id)
    end
  end
end

module ActiveRecord
  module ConnectionAdapters
    class MakaraAdapter
      def instance_variable_get(symbol)
        if symbol == :@config
          @current_wrapper.instance_variable_get :@config
        else
          super symbol
        end
      end
    end
  end
end

Clarity in Basic Usage instructions

The Basic Usage section of the repo's README has a here you go. link. Which this set of eyes went towards... and skip what follows. Thus, for one who is coming in from left field regarding AR and connections, I just don't know what to make of what follows.

a class needs to be defined class MyAwesomeSqlProxy < ::Makara::Proxy. OK. where? in an initialiser? I gather hijack_method is meant to send all selects to the slave. Where can I document myself to understand better :connect, :reconnect, etc. and thus make appropriate choices?

Reason being is that from the slave, I'm hitting Processing by Devise::SessionsController#create as HTML [...] ActiveRecord::StatementInvalid (PG::ReadOnlySqlTransaction: ERROR: cannot execute UPDATE in a read-only transaction, so clearly no hijacking is going on! Am also curious about the host (it could be a 3rd level domain, but I assume it is quicker to have the relevant server's ip-address and the web server (nginx) point the default configuration to the proper app - or am I mis-assuming?

Database connections not closing

Not sure if this relates to makara or not, but we are seeing database connections sit in TIME_WAIT for 8 hours on our rails servers running passenger, leading to massive numbers of connections on our database. This happens during normal operation over many hours, not during startup / shutdown.
This eventually leads to our main database reaching its connection limit. This happens to both read and write databases, but only affects our write database as connections from 4 server regions are coming in to it.
Restarting nginx in our case causes the connections to close and drop down to normal levels, which then will creep up again over the next 8 - 12 hours. Any ideas on this would be greatly appreciated. Thanks.
Screenshot shows our database connections when they change over and the effect a restart has http://cl.ly/image/3R1i141T3L0m

Transaction support

We have some workers that do heavy DB reads and a few writes, which looks like a perfect situation for Makara. They operate inside a transaction, though, and it appears that that forces all subsequent reads to use the master context. Is there any way of forcing reads to slaves while wrapped within an AR transaction?

record not found on master

hi,

we have some troubles understanding how your gem works.

here are our problems:

problem 1:

we have multiple services that currently share a single DB. service A (java) creates records, lets call them posts. service A notifies service B (rails) about the new record. service B tires to fetch the record from the DB. makara tells service B to use the slave, but the replication lag sometimes is to big so service B will not be able to find the record.

possible fix:

we could catch all record not found exceptions in application controller and retry the whole request with "stick to master" if the query that raised the exception was called on a slave.
i'm not really happy with this approach but i don't see any other option at the moment.

  • i couldn't find a way to find out if a query was executed on a slave. how could i do that?
  • how can i stick an ongoing request to the master?

problem 2 (slightly different):

service B (rails) creates a new article in the DB and then shares this article on facebook. the facebook crawler then crawls the the show page of the article and makara has no chance to rely on the cookie to dispatch queries to the master if the crawler hits the page before the master_ttl expires.

possible fix:

we could add the correct context to the url we shared and adjust the middleware to respect the get parameter.

i think that makara was designed for "simple" web applications that are used by browsers/users only and not for scenarios like ours. but i think with a few tweaks it would fit our needs and i would really love to help and figure these issue out.

br, simon

Disconnecting a read slave halts the entire application

It was my understanding that Makara should automatically deal with read slaves that become unavailable?
However when testing this (after it happened once in our production environment), our application actually throws the following:

Mysql2::Error: Unknown MySQL server host

Full stack trace:

mysql2 (0.3.13) lib/mysql2/client.rb:58:in `connect'
mysql2 (0.3.13) lib/mysql2/client.rb:58:in `initialize'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb:16:in `new'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb:16:in `mysql2_connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/makara-73ade49da3bc/lib/active_record/connection_adapters/makara_adapter.rb:31:in `underlying_connection_for'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/makara-73ade49da3bc/lib/active_record/connection_adapters/makara_adapter.rb:7:in `block in makara_connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/makara-73ade49da3bc/lib/makara/config_parser.rb:19:in `block in each_config'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/makara-73ade49da3bc/lib/makara/config_parser.rb:13:in `map'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/makara-73ade49da3bc/lib/makara/config_parser.rb:13:in `each_config'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/makara-73ade49da3bc/lib/active_record/connection_adapters/makara_adapter.rb:6:in `makara_connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/makara-73ade49da3bc/lib/active_record/connection_adapters/makara_mysql2_adapter.rb:7:in `makara_mysql2_connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:315:in `new_connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:325:in `checkout_new_connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:247:in `block (2 levels) in checkout'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:242:in `loop'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:242:in `block in checkout'
/usr/local/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:239:in `checkout'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:102:in `block in connection'
/usr/local/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:101:in `connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:410:in `retrieve_connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb:171:in `retrieve_connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb:145:in `connection'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/query_cache.rb:67:in `rescue in call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/query_cache.rb:61:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/actionpack/lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activesupport/lib/active_support/callbacks.rb:405:in `_run__2937628382615234653__call__2629546183784262930__callbacks'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activesupport/lib/active_support/callbacks.rb:405:in `__run_callback'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activesupport/lib/active_support/callbacks.rb:385:in `_run_call_callbacks'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activesupport/lib/active_support/callbacks.rb:81:in `run_callbacks'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/actionpack/lib/action_dispatch/middleware/callbacks.rb:27:in `call'
rack (1.4.5) lib/rack/sendfile.rb:102:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/actionpack/lib/action_dispatch/middleware/remote_ip.rb:31:in `call'
airbrake (3.1.12) lib/airbrake/rails/middleware.rb:13:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/railties/lib/rails/rack/logger.rb:32:in `call_app'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/railties/lib/rails/rack/logger.rb:16:in `block in call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activesupport/lib/active_support/tagged_logging.rb:22:in `tagged'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/railties/lib/rails/rack/logger.rb:16:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/actionpack/lib/action_dispatch/middleware/request_id.rb:22:in `call'
app/middleware/utf_url_middleware.rb:10:in `call'
rack (1.4.5) lib/rack/methodoverride.rb:21:in `call'
rack (1.4.5) lib/rack/runtime.rb:17:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/activesupport/lib/active_support/cache/strategy/local_cache.rb:72:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rack-throttle-3706324225c5/lib/rack/throttle/limiter.rb:34:in `call'
app/middleware/api_defender.rb:38:in `call'
rack (1.4.5) lib/rack/lock.rb:15:in `call'
rack-ssl (1.3.3) lib/rack/ssl.rb:27:in `call'
rack-cache (1.2) lib/rack/cache/context.rb:136:in `forward'
rack-cache (1.2) lib/rack/cache/context.rb:245:in `fetch'
rack-cache (1.2) lib/rack/cache/context.rb:185:in `lookup'
rack-cache (1.2) lib/rack/cache/context.rb:66:in `call!'
rack-cache (1.2) lib/rack/cache/context.rb:51:in `call'
airbrake (3.1.12) lib/airbrake/user_informer.rb:16:in `_call'
airbrake (3.1.12) lib/airbrake/user_informer.rb:12:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/railties/lib/rails/engine.rb:484:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/railties/lib/rails/application.rb:231:in `call'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bundler/gems/rails-59a35610459d/railties/lib/rails/railtie/configurable.rb:30:in `method_missing'
unicorn (4.6.3) lib/unicorn/http_server.rb:552:in `process_client'
unicorn (4.6.3) lib/unicorn/http_server.rb:632:in `worker_loop'
newrelic_rpm (3.6.1.88) lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb:22:in `call'
newrelic_rpm (3.6.1.88) lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb:22:in `block (4 levels) in <top (required)>'
unicorn (4.6.3) lib/unicorn/http_server.rb:500:in `spawn_missing_workers'
unicorn (4.6.3) lib/unicorn/http_server.rb:511:in `maintain_worker_count'
unicorn (4.6.3) lib/unicorn/http_server.rb:277:in `join'
unicorn (4.6.3) bin/unicorn_rails:209:in `<top (required)>'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bin/unicorn_rails:23:in `load'
/home/deploy/.bundler/roomorama_staging/ruby/2.0.0/bin/unicorn_rails:23:in `<main>'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.