You know how everyone is obsessed these days with scalability? Well, I am too. There’s a project of mine where I need to connect to multiple MySQL servers, depending on the current client id. The simplest implementation looks like this:
This works, but it creates a new connection on every call. Let’s suppose, we’re processing a queue and we’re handling events from different apps (customers). The cost of setting up a connection can easily outweigh the actual work. We need to cache that somehow.
Now, ActiveRecord::Base has a method called connection_config that returns, well, configuration of current connection. We can compare that to what we have on hands and, if they match, do not reconnect. Here’s how our code looks like now:
defself.use_table_for_appaidconfig=get_connection_configaidunlesscan_use_connection?(config)&&ActiveRecord::Base.connection.active?ActiveRecord::Base.establish_connectionconfigendenddefcan_use_connection?configcurrent_config=ActiveRecord::Base.connection_config# current config can have more keys than our config (or vice versa), so simple hash comparison doesn't work.config.eachdo|k,v|# if even a single parameter is different - can't reuse this connection.ifconfig[k]!=current_config[k]# TODO: log warningreturnfalseendendtrueend
Looks almost good. Now let’s extract this to a module for ease of re-using. Here’s the final code.
moduleSqlModelHelpersdefself.includedklassklass.send:extend,ClassMethodsendmoduleClassMethodsdefsetup_connectionaid# TODO: do not reestablish good connections.# 1. get config to connect# 2. compare with current config (ActiveRecord::Base.connection_config)# 3. if configs match and connection is open - do not establish_connectionconfig=get_connection_configaidunlesscan_use_connection?(config)&&ActiveRecord::Base.connection.active?ActiveRecord::Base.establish_connectionconfigendenddefcan_use_connection?configcurrent_config=ActiveRecord::Base.connection_configconfig.eachdo|k,v|ifconfig[k]!=current_config[k]# TODO: log warningreturnfalseendendtrueendendendclassMyModel<ActiveRecord::BaseincludeSqlModelHelpersdefself.use_table_for_appaidsetup_connectionaidtable_nameendend
Now if we want to use this functionality in some other models, we just include that module. This code can certainly be improved further, post your suggestions :)