I am encountering the 'mysql has gone away' error in Ruby after a certain amount of time that the script has been running.
I want to try to tell the mysql gem to auto-reconnect when the connection is lost.
My current code looks like the following:
def self.connect()
begin
if !##dbh.nil?
self.disconnect
end
##dbh = Mysql.real_connect(##server, ##user, ##pass, ##db)
puts "[+] Connected to the " + ##db + " database with user '" + ##user + "'"
rescue Mysql::Error => e
# log error
end
end
The following guide [0] says that the mysql gem has a 'reconnect' object variable, however, I am unsure of how to use it within my code.
How do I implement this option into the code above?
Thanks in advance,
Ryan
[0] http://www.tmtm.org/en/mysql/ruby/
EDIT ---
OK. I think I have figured it out.
I need to add ##dbh.reconnect = true after the ##dbh = Mysql.real_connect(##server, ##user, ##pass, ##db) line.
Note: According to a 'nice' chapy on IRC the mysql gem may not be the best Ruby gem to use.
If you're starting on a new project, the mysql2 gem is the way to go. It's an enormous improvement over the old version.
An attempt to Ruby-ize your example is:
def connect
begin
if (#dbh)
self.disconnect
end
#dbh = Mysql.real_connect(#server, #user, #pass, #db)
puts "[+] Connected to the #{#db} database with user '#{#user}'"
rescue Mysql::Error => e
# log error
end
end
The reason for using traditional # variables is you can use attr_accessor if you design your interface properly.
It's better to use a singleton instance than to wreck around with a singleton class. For instance:
class MyApp
def self.db
#db ||= Database.new
end
class Database
# Instance methods like initialize, connect, disconnect, etc.
end
end
You can use this like:
MyApp.db.connect
The advantage of using an instance of a class instead of a class directly is you can support more than one connection at a time.
Related
I'm using the Sequel gem which works great. However I'm trying to debug a multithreading bug so I activated the log (at the Sequel level : .i.e using a Logger when creating the connection to the database). My problem is , all the SQL logs coming from the different connections are tangled in the log file and there is no know which query correspond to which connection. Having a connection id or something added to the log would be really useful.
Is there a way to do so or an alternative solution ?
If there's nothing built-in, try monkey patching or changing the logger, or the call to it, so it prepends each log line with the thread's ID.
The relevant file in Sequel would be:
https://github.com/jeremyevans/sequel/blob/master/lib/sequel/database/logging.rb
Based on it, chances are you could subclass Logger and throw that in to make it work.
http://www.ruby-doc.org/stdlib-2.1.0/libdoc/logger/rdoc/Logger.html
If the Logger docs and its code is anything to go by, you can probably do what you want by overriding the add() method, e.g.:
def add(severity, message = nil, progname = nil, &block)
thread_msg = "thread: #{Thread.current.object_id}"
progname ||= #progname
if message.nil?
if block_given?
message = yield
else
message = progname
progname = #progname
end
end
message = "#{thread_msg}\n#{message}"
super(severity, message, progname, &block)
end
I'm working on ROR 3 app . I have added the following observer but I dont see any output as expected in the console or log file ( i have tried in both development and production modes)
cmd : rails g observer auditor
models:
class AuditorObserver < ActiveRecord::Observer
observe :excel_file
def after_update(excel_file)
excel_file.logger.info('New contact added!')
AuditTrail.new(execl_file, "UPDATED")
puts "*******************"
logger.info "********************************************"
end
end
application.rb:
config.active_record.observers = :auditor_observer
What am I missing in here? When I change the database (thru Mysql workbench/command line) I don't see any of the above lines getting executed.. neither after_update/after_save. But after_save works if I'm executing a query thru the app itself and do #excel.save
How else are we supposed to update data in DB so that we see the observer working????
When you bypass activerecord by modifying the database directly, you naturally bypass all of the activerecord callbacks.
So the answer is to update the data through the application, or to use database triggers instead.
I perodicially need to access a mysql database, my primary data store is mongo, which I access with mongoid. I want to know the best way to manage connections to mysql (with the mysql2 gem - 0.2.7) without using active record.
I current do the following ...
# In config/initializers/mysql.rb
class MySqlConnection
def self.client
#client ||= Mysql2::Client.new(host: ENV['mysql_host'],
username: ENV['mysql_username'],
password: ENV['mysql_password'],
database: ENV['mysql_database'])
end
end
and then I use connection, like so ...
rows_q = "SELECT * FROM amaizng_table WHERE great_column = '#{cool_value}' "
rows = ::MySqlConnection.client.query(rows_q)
And everything is working okay -- but I have a sneaking suspicion that I am doing something horribly wrong, and things are going to explode down the road.
Also Note, the application is hosted on heroku
Anyone know the best way to approach this?
Thanks!
Jonathan
why, just WHY would you get rid of ActiveRecord's awesomeness (or any other ORM, really) ?
class Amazing < ActiveRecord::Base
establish_connection :mysql_database
end
so simple it hurts. See this for more details.
I've been searching all over for tips on this and have not really had any luck so far. With the mysql2 gem, trying to execute a stored procedure that returns multiple result sets gives me an unable to return results in this context error. I found someone had suggested to use the mysql gem instead (which I can't find an explanation of what's different between the two and what I might encounter by switching), and with that I've had more progress.
Here's what I have so far:
>> db = ActiveRecord::Base.connection.raw_connection
=> #<Mysql:0x1056ae3d8>
>> ActiveRecord::Base.connection.select_all("CALL p_rpt_test('', '');")
=> [{"Header"=>"Client,Project,Type,Due Date,Assigned To"}]
>> db.more_results?
=> true
>> db.next_result
Mysql::Error: Commands out of sync; you can't run this command now
from (irb):3:in `next_result'
from (irb):3
Does anyone know of a way to get this to work, with mysql2 or mysql gems? The app is running rails 3.0.1.
Ok well I have no figured out how to get AR to do this so I've ended up just going low level and using the mysql driver itself, which mostly works...
data = Array.new
db = ActiveRecord::Base.connection.raw_connection
header = db.query("CALL #{self.proc}(#{args});")
header.each {|r| data << r}
if db.next_result
rows = db.store_result
rows.each {|r| data << r}
end
ActiveRecord::Base.connection.reconnect!
It works, but I can't imagine there's not a better way. Also I have to reconnect after this or I get an error on the next query, and I haven't found a way to properly close the session. Oh and I have to use the mysql gem and not mysql2.
Grrrrr.
We can use header.to_hash to get an array of hash, or header.rows to get an array of array.
Follow this http://api.rubyonrails.org/classes/ActiveRecord/Result.html
We are using Sinatra and Sequel for a small API implementation. The problem we have however is that on every page request Sequel opens new connections to MySQL, and keeps them open till they timeout, or you restart Apache.
There's not a lot of documentation on how to reuse connections, so any help, explanations, and/or pointers in the right direction would help.
I wrapped the Sequel stuff in a tiny wrapper and reuse this wrapper, like this:
get '/api/:call' do
##api ||= SApi.new
##api.call(params[:call])
end
class SApi
def initialize
connect
end
def connect
#con = Sequel.connect("...")
end
def call(x)
#handle call using #con
end
end
Alternatively, you can call #con.disconnect once you're finished or call Sequel.connect using a block:
Sequel.connect("...") do |c|
# work with c
end #connection closed
We figured out what we were doing wrong. It was rather stupid, we initialized Sequel in a before filter in Sinatra.
So instead we do:
DB = Sequel.mysql("...")
Then we simply use the DB constant to use Sequel.