describe 'activerecord-mysql-reconnect' do it 'select all' do expect { expect(Employee.all.length).to eq(300024) mysql_restart expect(Employee.all.length).to eq(300024) }.to_not raise_error end it 'count' do expect { expect(Employee.count).to eq(300024) mysql_restart expect(Employee.count).to eq(300024) }.to_not raise_error end it 'on select' do expect { th = thread_run {|do_stop| expect(Employee.where(:id => 1).pluck('sleep(10) * 0')).to eq([0]) } mysql_restart expect(Employee.count).to be >= 300024 th.join }.to_not raise_error end it 'on insert' do expect { th = thread_run {|do_stop| emp = nil mysql2_error('MySQL server has gone away') do emp = Employee.create( :emp_no => 1, :birth_date => Time.now, :first_name => "' + sleep(10) + '", :last_name => 'Tiger', :hire_date => Time.now ) end do_stop.call expect(emp.id).to eq(300025) expect(emp.emp_no).to eq(1) } mysql_restart expect(Employee.count).to be >= 300024 th.join }.to_not raise_error end it 'op update' do expect { th = thread_run {|do_stop| emp = Employee.where(:id => 1).first emp.first_name = "' + sleep(10) + '" emp.last_name = 'ZapZapZap' mysql2_error('MySQL server has gone away') do emp.save! end do_stop.call emp = Employee.where(:id => 1).first expect(emp.last_name).to eq('ZapZapZap') } mysql_restart expect(Employee.count).to eq(300024) th.join }.to_not raise_error end it 'without_retry' do expect { ActiveRecord::Base.without_retry do Employee.count mysql_restart Employee.count end }.to raise_error(ActiveRecord::StatementInvalid) end it 'transaction' do unless /MyISAM/i =~ ENV['ACTIVERECORD_MYSQL_RECONNECT_ENGINE'] expect { expect(Employee.count).to eq(300024) mysql2_error('MySQL server has gone away') do ActiveRecord::Base.transaction do emp = Employee.create( :emp_no => 1, :birth_date => Time.now, :first_name => 'Scott', :last_name => 'Tiger', :hire_date => Time.now ) expect(emp.id).to eq(300025) expect(emp.emp_no).to eq(1) mysql_restart emp = Employee.create( :emp_no => 2, :birth_date => Time.now, :first_name => 'Scott', :last_name => 'Tiger', :hire_date => Time.now ) expect(emp.id).to eq(300025) expect(emp.emp_no).to eq(2) end end expect(Employee.count).to eq(300025) }.to_not raise_error end end it 'retryable_transaction' do unless /MyISAM/i =~ ENV['ACTIVERECORD_MYSQL_RECONNECT_ENGINE'] expect { expect(Employee.count).to eq(300024) mysql2_error('MySQL server has gone away') do ActiveRecord::Base.retryable_transaction do emp = Employee.create( :emp_no => 1, :birth_date => Time.now, :first_name => 'Scott', :last_name => 'Tiger', :hire_date => Time.now ) expect(emp.id).to eq(300025) expect(emp.emp_no).to eq(1) mysql_restart emp = Employee.create( :emp_no => 2, :birth_date => Time.now, :first_name => 'Scott', :last_name => 'Tiger', :hire_date => Time.now ) expect(emp.id).to eq(300026) expect(emp.emp_no).to eq(2) mysql_restart emp = Employee.create( :emp_no => 3, :birth_date => Time.now, :first_name => 'Scott', :last_name => 'Tiger', :hire_date => Time.now ) expect(emp.id).to eq(300027) expect(emp.emp_no).to eq(3) end end expect(Employee.count).to eq(300027) }.to_not raise_error end end it 'retry new connection' do expect { ActiveRecord::Base.clear_all_connections! mysql_restart expect(Employee.count).to eq(300024) }.to_not raise_error end it 'retry verify' do expect { th = thread_run {|do_stop| mysql_stop sleep 10 mysql_start } ActiveRecord::Base.connection.verify! th.join }.to_not raise_error end it 'retry reconnect' do expect { th = thread_run {|do_stop| mysql_stop sleep 10 mysql_start } ActiveRecord::Base.connection.reconnect! th.join }.to_not raise_error end it 'disable reconnect' do disable_retry do expect { expect(Employee.all.length).to eq(300024) mysql_restart expect(Employee.all.length).to eq(300024) }.to raise_error(ActiveRecord::StatementInvalid) end expect { expect(Employee.all.length).to eq(300024) mysql_restart expect(Employee.all.length).to eq(300024) }.to_not raise_error end it 'read only (read)' do enable_read_only do expect { expect(Employee.all.length).to eq(300024) mysql_restart expect(Employee.all.length).to eq(300024) }.to_not raise_error end end it 'read only (write)' do enable_read_only do expect { lock_table th = thread_run {|do_stop| mysql2_error('MySQL server has gone away') do emp = Employee.create( :emp_no => 1, :birth_date => Time.now, :first_name => 'Scott', :last_name => 'Tiger', :hire_date => Time.now ) end } mysql_restart th.join }.to raise_error(ActiveRecord::StatementInvalid) end end it 'lost connection' do sql = "INSERT INTO `employees` (`birth_date`, `emp_no`, `first_name`, `hire_date`, `last_name`) VALUES ('2014-01-09 03:22:25', 1, 'Scott', '2014-01-09 03:22:25', 'Tiger')" expect { ActiveRecord::Base.connection.execute(sql) }.to_not raise_error lock_table mysql2_error('Lost connection to MySQL server during query') do expect { th = thread_run {|do_stop| ActiveRecord::Base.connection.execute(sql) } mysql_restart th.join }.to raise_error(ActiveRecord::StatementInvalid) end end it 'force retry' do sql = "INSERT INTO `employees` (`birth_date`, `emp_no`, `first_name`, `hire_date`, `last_name`) VALUES ('2014-01-09 03:22:25', 1, 'Scott', '2014-01-09 03:22:25', 'Tiger')" expect { ActiveRecord::Base.connection.execute(sql) }.to_not raise_error lock_table mysql2_error('Lost connection to MySQL server during query') do expect { th = thread_run {|do_stop| force_retry do ActiveRecord::Base.connection.execute(sql) end } mysql_restart th.join }.to_not raise_error end end it 'read-only=1' do mysql2_error('The MySQL server is running with the --read-only option so it cannot execute this statement:') do expect { expect(Employee.all.length).to eq(300024) mysql_restart expect(Employee.all.length).to eq(300024) }.to_not raise_error end end it 'retry specific database' do retry_databases(:employees2) do expect { expect(Employee.all.length).to eq(300024) mysql_restart expect(Employee.all.length).to eq(300024) }.to raise_error(ActiveRecord::StatementInvalid) end expect { expect(Employee.all.length).to eq(300024) mysql_restart expect(Employee.all.length).to eq(300024) }.to_not raise_error end end