Skip to content
This repository

Postgresql auto reconnect 2 #6654

Merged
merged 3 commits into from over 1 year ago

6 participants

Steve Jorgensen Rafael Mendonça França Carlos Antonio da Silva John Butler Aaron Patterson Andrés Mejía
Steve Jorgensen

Fixes not-quite-working PostgreSQL auto-reconnection on Connection#verify! and puts test coverage in place so that it should continue to work.

Rafael Mendonça França
Owner

Related with #6557.

Steve Jorgensen

Right. Based on feedback from #6557, I started again putting test coverage on the re-connect behavior that was supposed to be fixed by #6477. It turned out that was not quite working right because of an incompatible change to ...::PostgteSQLAdapter#translate_exception, and there had been no test coverage to reveal this problem.

Steve Jorgensen

Pulled master and rebased, and re-ran tests to keep the branch fresh.

Anyone going to accept this? I want to get it fixed on Edge, so I can proceed to get it fixed on the Rails versions used at the company I work for, where this will resolve an open issue that can affect our users.

Rafael Mendonça França
Owner

Could you squash the commits? I'll ask @tenderlove to review this.

Steve Jorgensen

Sure -- all 3 together, or just squash the warning fix?

It might be easier for me to cherry pick the commits onto other version branches if the other 2 are separate.I don't know if the change that c424ab0 fixes exists on the other branches.

Steve Jorgensen

While awaiting reply, I squashed the warning fix & force-pushed.

Steve Jorgensen

Ping.

Steve Jorgensen

Ping

Steve Jorgensen

Ping

Rafael Mendonça França
Owner

@stevecj Aaron is already assigned to this issue. He will take a look when he have some time.

Steve Jorgensen

OK -- thx for the update.

activerecord/test/cases/adapters/postgresql/connection_test.rb
((24 lines not shown))
  92
+      CODE
  93
+
  94
+      begin
  95
+        @connection.verify!
  96
+        new_connection_pid = @connection.query('select pg_backend_pid()')
  97
+      ensure
  98
+        connection_class.class_eval <<-CODE
  99
+          alias   query    query_unfake
  100
+          undef query_fake
  101
+        CODE
  102
+      end
  103
+
  104
+      assert_equal original_connection_pid, new_connection_pid, "Should have a new underlying connection pid"
  105
+    end
  106
+
  107
+    # Must have with_manual_interventions set to false for this
2
Andrés Mejía
andmej added a note June 20, 2012

Shouldn't this be "Must have with_manual_interventions set to true for this test to run"?

Steve Jorgensen
stevecj added a note June 20, 2012

Yes. I'll amend that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Steve Jorgensen

Just rebased, re-ran tests & force-pushed to keep this fresh -- since it's been sitting here for quite a while.

Steve Jorgensen

Again, rebased & re-ran tests to keep the branch alive and fresh. Any chance of a pull some day?

Carlos Antonio da Silva

@stevecj thanks for keeping this up-to-date with master, we surely appreciate. @tenderlove is aware of your pull request, it has already been discussed a few times, and it'll be probably merged in sooner or later. Thanks!

activerecord/test/cases/adapters/postgresql/connection_test.rb
((8 lines not shown))
  88
+      # Fail with bad connection after next query attempt.
  89
+      connection_class = class << @connection ; self ; end
  90
+      connection_class.class_eval <<-CODE
  91
+        def query_fake(*args)
  92
+          if @called ||= false
  93
+            @connection.stubs(:status).returns(PCconn::CONNECTION_BAD)
  94
+            raise PGError
  95
+          else
  96
+            @called = true
  97
+            @connection.unstub(:status)
  98
+            query_unfake(*args)
  99
+          end
  100
+        end
  101
+
  102
+        alias  query_unfake    query
  103
+        alias     query     query_fake
2
Carlos Antonio da Silva Owner

What's up with the spaces here? Can you check that (and the other below)?

Steve Jorgensen
stevecj added a note July 02, 2012

I think I tried them left_aligned, and thought it didn't read well, so kinda' made centered columns instead. I grant you that's pretty non-standard though. I'll fix those if you like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
added some commits May 21, 2012
Don't crash exception translation w/ nil result attribute.
Exception.result is nil when attempting a query after PostgreSQL
disconnect, resulting in new exception:
NoMethodError: undefined method `error_field' for nil:NilClass
0d63cda
Simulated & actual (manual/skipped) PostgreSQL auto-reconnection tests. 6d5f4de
Stop being silly with formatting of method aliasing. 4b1bca0
Steve Jorgensen

I just fixed the silly formatting, per Carlos' comment & rebased onto the latest master.

Anything else I can do to help move this along?

Aaron Patterson tenderlove merged commit 0dc356e into from July 25, 2012
Aaron Patterson tenderlove closed this July 25, 2012
Steve Jorgensen

Thanks :)

John Butler

Will this be backported to Rails 3.2.x?

Aaron Patterson
Owner

If someone is willing to do the work, yes. I think there are other commits than this pull request for the bug to be fixed on 3-2-stable though.

Steve Jorgensen

FWICS, the bug that this fixes does not actually exist on the 3.x branches. The bug that was fixed by #6477 does though, so that's the fix that needs to be backported.

The test coverage from here would be helpful in preventing further regressions of psql reconnection functionality regardless of the cause, and so might be useful to backport. Please note, however, that I badly mangled the first of those tests, and subsequently mangled my initial attempt at fixing it, which I rushed through due to my embarrassment at the initial test mangling. Therefore, also see #7292 and #7294.

I can probably be available to work this back-porting, but it could take me a week or 3 to squeeze it into my schedule.

Steve Jorgensen stevecj referenced this pull request September 13, 2012
Merged

3 2 stable #7632

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 3 unique commits by 1 author.

Jul 16, 2012
Don't crash exception translation w/ nil result attribute.
Exception.result is nil when attempting a query after PostgreSQL
disconnect, resulting in new exception:
NoMethodError: undefined method `error_field' for nil:NilClass
0d63cda
Simulated & actual (manual/skipped) PostgreSQL auto-reconnection tests. 6d5f4de
Stop being silly with formatting of method aliasing. 4b1bca0
This page is out of date. Refresh to see the latest.
3  activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -474,6 +474,7 @@ def active?
474 474
       def reconnect!
475 475
         clear_cache!
476 476
         @connection.reset
  477
+        @open_transactions = 0
477 478
         configure_connection
478 479
       end
479 480
 
@@ -1381,7 +1382,7 @@ def postgresql_version
1381 1382
         UNIQUE_VIOLATION      = "23505"
1382 1383
 
1383 1384
         def translate_exception(exception, message)
1384  
-          case exception.result.error_field(PGresult::PG_DIAG_SQLSTATE)
  1385
+          case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE)
1385 1386
           when UNIQUE_VIOLATION
1386 1387
             RecordNotUnique.new(message, exception)
1387 1388
           when FOREIGN_KEY_VIOLATION
72  activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -81,5 +81,77 @@ def test_schema_names_logs_name
81 81
       assert_equal 'SCHEMA', @connection.logged[0][1]
82 82
     end
83 83
 
  84
+    def test_reconnection_after_simulated_disconnection_with_verify
  85
+      assert @connection.active?
  86
+      original_connection_pid = @connection.query('select pg_backend_pid()')
  87
+
  88
+      # Fail with bad connection after next query attempt.
  89
+      connection_class = class << @connection ; self ; end
  90
+      connection_class.class_eval <<-CODE
  91
+        def query_fake(*args)
  92
+          if @called ||= false
  93
+            @connection.stubs(:status).returns(PCconn::CONNECTION_BAD)
  94
+            raise PGError
  95
+          else
  96
+            @called = true
  97
+            @connection.unstub(:status)
  98
+            query_unfake(*args)
  99
+          end
  100
+        end
  101
+
  102
+        alias query_unfake query
  103
+        alias query        query_fake
  104
+      CODE
  105
+
  106
+      begin
  107
+        @connection.verify!
  108
+        new_connection_pid = @connection.query('select pg_backend_pid()')
  109
+      ensure
  110
+        connection_class.class_eval <<-CODE
  111
+          alias query query_unfake
  112
+          undef query_fake
  113
+        CODE
  114
+      end
  115
+
  116
+      assert_equal original_connection_pid, new_connection_pid, "Should have a new underlying connection pid"
  117
+    end
  118
+
  119
+    # Must have with_manual_interventions set to true for this
  120
+    # test to run.
  121
+    # When prompted, restart the PostgreSQL server with the
  122
+    # "-m fast" option or kill the individual connection assuming
  123
+    # you know the incantation to do that.
  124
+    # To restart PostgreSQL 9.1 on OS X, installed via MacPorts, ...
  125
+    # sudo su postgres -c "pg_ctl restart -D /opt/local/var/db/postgresql91/defaultdb/ -m fast"
  126
+    def test_reconnection_after_actual_disconnection_with_verify
  127
+      skip "with_manual_interventions is false in configuration" unless ARTest.config['with_manual_interventions']
  128
+
  129
+      original_connection_pid = @connection.query('select pg_backend_pid()')
  130
+
  131
+      # Sanity check.
  132
+      assert @connection.active?
  133
+
  134
+      puts 'Kill the connection now (e.g. by restarting the PostgreSQL ' +
  135
+           'server with the "-m fast" option) and then press enter.'
  136
+      $stdin.gets
  137
+
  138
+      @connection.verify!
  139
+
  140
+      assert @connection.active?
  141
+
  142
+      # If we get no exception here, then either we re-connected successfully, or
  143
+      # we never actually got disconnected.
  144
+      new_connection_pid = @connection.query('select pg_backend_pid()')
  145
+
  146
+      assert_not_equal original_connection_pid, new_connection_pid,
  147
+        "umm -- looks like you didn't break the connection, because we're still " +
  148
+        "successfully querying with the same connection pid."
  149
+
  150
+      # Repair all fixture connections so other tests won't break.
  151
+      @fixture_connections.each do |c|
  152
+        c.verify!
  153
+      end
  154
+    end
  155
+
84 156
   end
85 157
 end
2  activerecord/test/config.example.yml
... ...
@@ -1,5 +1,7 @@
1 1
 default_connection: <%= defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' %>
2 2
 
  3
+with_manual_interventions: false
  4
+
3 5
 connections:
4 6
   jdbcderby:
5 7
     arunit:  activerecord_unittest
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.