activegraph icon indicating copy to clipboard operation
activegraph copied to clipboard

migrations timing out with simple drop_constraint / fixes with disabled_transactions!?

Open leviwilson opened this issue 6 years ago • 5 comments

We have ran into seemingly random issues particularly with regard to either adding or removing constraints. A recent example of this is a simple migration that is defined like so:

class RemoveDocumentTypeConstraints < Neo4j::Migrations::Base
  def up
    drop_constraint :DocumentType, :uuid
    drop_constraint :DocumentType, :external_id
  end

  def down
    add_constraint :DocumentType, :uuid
    add_constraint :DocumentType, :external_id
  end
end

In a project of ours we have, adding this migration causes the DROP CONSTRAINT to timeout when all of the migrations run against an empty graph (to start out with).

Why? I'm unsure. But if I add a disable_transactions! in that definition everything is hunky dory.

Here is a sample stack trace that happens without having disable_transactions! in there:

== 20171128152132 RemoveDocumentTypeConstraints: running... ====================
 CYPHER DROP CONSTRAINT ON (n:`DocumentType`) ASSERT n.`uuid` IS UNIQUE
rake aborted!
Faraday::TimeoutError: request timed out
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/adapters/faraday.rb:100:in `block in request'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/callbacks.rb:128:in `block in execute_callbacks'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/callbacks.rb:127:in `each'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/callbacks.rb:127:in `execute_callbacks'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/operations.rb:35:in `finish'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/easy_factory.rb:159:in `block in set_callback'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/ethon-0.10.1/lib/ethon/easy/response_callbacks.rb:68:in `block in complete'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/ethon-0.10.1/lib/ethon/easy/response_callbacks.rb:68:in `each'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/ethon-0.10.1/lib/ethon/easy/response_callbacks.rb:68:in `complete'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/ethon-0.10.1/lib/ethon/easy/operations.rb:33:in `perform'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/operations.rb:16:in `run'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/cacheable.rb:18:in `run'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/block_connection.rb:31:in `run'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/stubbable.rb:25:in `run'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/request/before.rb:26:in `run'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/adapters/faraday.rb:82:in `perform_request'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/typhoeus-1.3.0/lib/typhoeus/adapters/faraday.rb:72:in `call'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/faraday_middleware-0.10.1/lib/faraday_middleware/response_middleware.rb:30:in `call'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/faraday_middleware-0.10.1/lib/faraday_middleware/request/encode_json.rb:23:in `call'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/faraday-0.13.1/lib/faraday/rack_builder.rb:141:in `build_response'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/faraday-0.13.1/lib/faraday/connection.rb:387:in `run_request'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/cypher_session/adaptors/http.rb:129:in `block (2 levels) in request'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/cypher_session/adaptors/http.rb:187:in `wrap_connection_failed!'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/cypher_session/adaptors/http.rb:128:in `block in request'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/instrumentable.rb:29:in `block (3 levels) in instrument'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/activesupport-5.0.6/lib/active_support/notifications.rb:164:in `block in instrument'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/activesupport-5.0.6/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/activesupport-5.0.6/lib/active_support/notifications.rb:164:in `instrument'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/instrumentable.rb:29:in `block (2 levels) in instrument'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/cypher_session/adaptors/http.rb:127:in `call'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/cypher_session/adaptors/http.rb:127:in `request'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/cypher_session/adaptors/http.rb:141:in `get'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/cypher_session/adaptors/http.rb:62:in `constraints'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/cypher_session.rb:36:in `block (2 levels) in <class:CypherSession>'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/label.rb:100:in `constraints'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/core/label.rb:124:in `constraint?'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/helpers/schema.rb:27:in `drop_constraint'
/Users/lwilson/git/super_project/db/neo4j/migrate/20171128152132_remove_document_type_constraints.rb:6:in `up'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:56:in `public_send'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:56:in `block (2 levels) in run_migration'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:71:in `log_queries'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:56:in `block in run_migration'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/active_base.rb:40:in `block in run_transaction'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-core-7.0.9/lib/neo4j/transaction.rb:135:in `run'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/active_base.rb:39:in `run_transaction'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:66:in `migration_transaction'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:56:in `run_migration'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:33:in `migrate_up'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:16:in `block in migrate'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/base.rb:15:in `migrate'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/runner.rb:127:in `block in migrate'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/runner.rb:133:in `migration_message'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/runner.rb:125:in `migrate'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/runner.rb:26:in `block in all'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/runner.rb:24:in `each'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/migrations/runner.rb:24:in `all'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/tasks/migration.rake:116:in `block (3 levels) in <top (required)>'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/neo4j-8.1.5/lib/neo4j/tasks/migration.rake:45:in `block (2 levels) in <top (required)>'
/Users/lwilson/.rvm/gems/ruby-2.3.1/gems/rake-12.1.0/exe/rake:27:in `<top (required)>'
/Users/lwilson/.rvm/gems/ruby-2.3.1/bin/ruby_executable_hooks:15:in `eval'
/Users/lwilson/.rvm/gems/ruby-2.3.1/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => neo4j:migrate:all
(See full trace by running task with --trace)

Only thing I could maybe think of that might contribute to the issue is the fact that in an earlier migration that constraint would've been initially added?

Just curious if anyone else has ran into this issue or could provide insight as to when we should or should not be using disable_transactions! as the documentation only seems to suggest that you should only need to use that if you're mixing schema changes with node creation, etc.

Runtime information:

Neo4j database version: neo4j gem version: 8.1.5 neo4j-core gem version: 7.0.9

leviwilson avatar Dec 18 '17 20:12 leviwilson

@leviwilson I'm guessing this is a limitation of Neo4j. Can you try checking the database logs to see if it contains more information about the failure? Faraday::TimeoutError: request timed out isn't very specific.

jorroll avatar Dec 20 '17 22:12 jorroll

@thefliik oh, surely! Understood that's not the root cause; my 🤔 is that for whatever reasons, within a transaction the request is taking longer than the default 60s, whereas with disable_transactions! the request takes place immediately.

I can look at the logs, but I was more curious what was happening under the scenes to cause it to go well beyond what it takes in the absence of a transaction.

leviwilson avatar Dec 21 '17 01:12 leviwilson

It's been a while but I remember this being a Neo4j limitation. Certain schema modifications within transactions would always time out.

subvertallchris avatar Dec 21 '17 01:12 subvertallchris

Before you created this issue, I was under the impression that Neo4j only allowed one schema modification per transaction. The fact that you were able to add two constraints as part of the original migration calls my belief into question though. I was thinking that, perhaps, the Neo4j logs might contain some error info / explanation that never made it to Faraday.

jorroll avatar Dec 21 '17 01:12 jorroll

@thefliik ahh, I gotcha. I hadn't even considered that to be honest. I'll see if that yields any details 👍

leviwilson avatar Dec 21 '17 02:12 leviwilson