0

Before we start, yes, I know using Ruby's Timeout is a horrible idea. But this is more of a thought experiment.

Let's say I have some Ruby code wrapped in a Timeout::timeout block that does a whole bunch of SQL transactions (via ActiveRecord), from SELECTs, UPDATEs and INSERTs. Given the nature of Timeout, we could abort in the midst of preparing or waiting for a SQL transaction to finish.

In theory, if the request to the DB is sent before the Ruby timeout interrupt, the transaction would complete on the DB but the client just wouldn't be able to respond to the completion. And of course, depending on the context of the Ruby code, the data could ultimately be incomplete if there are subsequent transactions needed in order for my model to be considered complete and stable, and whatever other possible side effects due to the code not finishing fully.

Are there any other possible dangers or side effects to be concerned with? Is there a chance the transaction could hang or fail in some other way? Or is there just too much contextual level knowledge needed about the data and application to say?

Display name
  • 1,109
  • 1
  • 15
  • 31
  • 1
    Since ActiveRecord manages its connection pool by wrapping SQL statement execution in `ActiveRecord::Base.connection_pool.with_connection { ... }`, I would imagine you could get a connection pool leak if `Timeout` killed the execution thread before it was able to check the thread back in. I don't think the connection would hang since it would eventually commit or abort (see https://dba.stackexchange.com/questions/81408/is-a-postgres-long-running-query-aborted-if-the-connection-is-lost-broken ). Not marking as a full answer, since it's more an intuitive stab than something I'm sure of. – David Bodow Jun 08 '19 at 20:36
  • There's a good treatment of multithreading in `Timeout` here, though it sounds like you may already be aware of the issues it can cause: https://flushentitypacket.github.io/ruby/2015/02/21/ruby-timeout-how-does-it-even-work.html – David Bodow Jun 08 '19 at 20:39
  • Ah excellent point. Perhaps this could be salvaged in the Timeout's `rescue` with a call to https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionHandler.html#method-i-clear_active_connections-21? – Display name Jun 08 '19 at 22:01
  • You could probably write handlers for that and anything else that may go wrong. But practically speaking, you really wouldn't want to do this; find a better pattern. For ex. our customers send us various queries (potentially too large!), and we send them off to an internal-only service over TCP that fires off & normalizes the PG query. The advantage is the internal client can manage timeout & PG will stop processing soon after that. It works well for queries, but if you're dealing with commands, that gets messier since they can commit but not return. But in that case, another DB may be better – David Bodow Jun 08 '19 at 22:19
  • Regarding leaked connections, `ActiveRecord::ConnectionPool` does specify a `reap` method that would handle this, and it gets called in `acquire_connection` – Display name Jun 10 '19 at 15:04

0 Answers0