neo4jrb / activegraph

An active model wrapper for the Neo4j Graph Database for Ruby.
http://neo4jrb.io
MIT License
1.4k stars 276 forks source link

No session, please create a session first with Neo4j::Session.open(:server_db) or :embedded_db #1385

Open kroyagis opened 7 years ago

kroyagis commented 7 years ago

I tried looking everywhere but couldn't find the solution. When I run,

config.around do |example|
  Neo4j::Transaction.run do |tx|
    example.run
      tx.mark_failed
    end
  end

it throws No session, please create a session first with Neo4j::Session.open(:server_db) or :embedded_db error.

Additional information which could be helpful if relevant to your issue:

Code example (inline, gist, or repo)

Runtime information:

Neo4j database version: 3.1.4 neo4j gem version: 8.0.17 neo4j-core gem version: 7.1.2

cheerfulstoic commented 7 years ago

If you're using the neo4j gem, you need to setup the session (docs for: without Rails and with Rails). I'm guessing that's the problem. That error message should probably be updated to reflect the new API...

kroyagis commented 7 years ago

I've included

config.neo4j.session.type = :http # or :bolt
config.neo4j.session.url = 'http://localhost:7475'

in all the environments' Rails.application.configure block, but it's not working. If I go into rails console test and do Neo4j::Session.open(:server_db) but the response I get the following error:

ETHON: performed EASY effective_url=http://localhost:7474/ response_code=0 return_code=couldnt_connect total_time=0.005008
Faraday::ConnectionFailed: Couldn't connect to server

How come it's still connecting to port 7474, although I configured it to 7475?

For the reference, here is what my application.rb looks like:

require File.expand_path('../boot', __FILE__)
require 'rails/all'
require 'neo4j/railtie'

Bundler.require(*Rails.groups)

module Api
  class Application < Rails::Application
    config.autoload_paths << Rails.root.join("lib")
    config.active_record.raise_in_transactional_callbacks = true
    config.neo4j.session.type = :http
    config.neo4j.session.url = 'http://localhost:7475'
    config.neo4j.session.options = {initialize: { ssl: { verify: true }}}

    # After 8.0.x of `neo4j` gem
    # Switched to allowing a "configurator" since everything can be done there
    config.neo4j.session.options = {
      faraday_configurator: proc do |faraday|
        # The default configurator uses typhoeus (it was `Faraday::Adapter::NetHttpPersistent` for `neo4j-core` < 7.1.0), so if you override the configurator you must specify this
        # faraday.adapter :typhoeus
        # Optionally you can instead specify another adaptor
        faraday.use Faraday::Adapter::NetHttpPersistent

        # If you need to set options which would normally be the second argument of `Faraday.new`, you can do the following:
        faraday.options[:open_timeout] = 5
        faraday.options[:timeout] = 65
        faraday.ssl[:verify] = true
      end
    }
    config.web_console.development_only = false

    ActiveModel::Serializer.setup do |config|
      config.embed_in_root = true
      config.embed_in_root_key = :linked
    end

    config.middleware.use Rack::Cors do
      allow do
        origins '*'
        resource '*',
          headers: :any,
          expose: ['X-API-TOKEN','X-API-EMAIL'],
          methods: [:get, :post, :options, :delete, :put]
      end
    end

    config.before_configuration do
      env_file = File.join(Rails.root, 'config', 'local_env.yml')
      YAML.load(File.open(env_file)).each do |key, value|
        ENV[key.to_s] = value
      end if File.exists?(env_file)
    end
  end
end
kroyagis commented 7 years ago

in the console, Neo4j::Session.open(:server_db, 'http://localhost:7475 works.

ETHON: Libcurl initialized
ETHON: performed EASY effective_url=http://localhost:7475/ response_code=200 return_code=ok total_time=0.006738
ETHON: performed EASY effective_url=http://localhost:7475/db/data/ response_code=200 return_code=ok total_time=0.000775
=> Neo4j::Server::CypherSession url: 'http://localhost:7475/db/data/' version: '3.1.4'

So I guess it's a configuration issue?

cheerfulstoic commented 7 years ago

If you're connecting via HTTPS you may need to do:

config.neo4j.session.type = :http
config.neo4j.session.url = 'https://localhost:7475'

Also, Neo4j::Session is from the old, deprecated API in neo4j-core. For the new API you would do:

http_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('https://localhost:7475')
neo4j_session = Neo4j::Core::CypherSession.new(http_adaptor)

You should also check to see if you have a config/neo4j.yml. That might have defaults which are overwriting the application.rb (though application.rb should have priority, I think)

kroyagis commented 7 years ago

As far as I can tell, config/neo4j.yml seems to be configured right.

development:
  type: http
  url: http://localhost:7100

test:
  type: http
  url: http://localhost:7475

production:
  type: http
  url: http://neo4j:password@localhost:7000

Also, I already have config.neo4j.session.type = :http and config.neo4j.session.url = 'https://localhost:7475' in the application.rb. I don't know where that ETHON thing is coming from, and why it's still trying to connect to http://localhost:7474.

cheerfulstoic commented 7 years ago

I wrote about config.neo4j.session.url because in your code you had http instead of https

ETHON comes from the typhoeus gem which is the driver which the neo4j-core gem uses for Faraday.

I'm not really sure why you're having the issue, unfortunately. The gem should probably have better debugging output to say where it's getting the URL from. The only other thing that I can think of is that you're looking at the local_env.yml file. Maybe that has a NEO4J_URL environment variable specified?

kroyagis commented 7 years ago

Thank you for helping me out. Switching to https gave me http.rb:923:in 'connect': too many connection resets. The reason for switching to 8.0.x was to be able to make indexed spatial queries in neo4jrb_spatial plugin, because they removed the spatial_index from the newer version. I'll revert back to 7.1.0 for now, and keep researching. I will let you know if things work out! :) Thank you so much for your help.

jorroll commented 7 years ago

@kroyagis, is it possible this issue is related to https://github.com/neo4jrb/neo4j/issues/1357 ?

If so, you might be able to fix the issue by using Neo4j::ActiveBase.run_transaction instead

jorroll commented 6 years ago

@kroyagis & @cheerfulstoic , while running into another issue with Neo4j, I decided to troubleshoot by creating a new blank project with

rails new issue-test -m http://neo4jrb.io/neo4j/neo4j.rb -B
rake neo4j:install[community-3.1.4]

and suddenly I ran into this problem.

By adding an initializer to rails with the following code, the problem was solved.

require 'neo4j/core/cypher_session/adaptors/http'
neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('http://localhost:7474')
Neo4j::ActiveBase.on_establish_session { Neo4j::Core::CypherSession.new(neo4j_adaptor) }

Supposedly, this initialization should be handled automatically by a railtie, but for whatever reason I needed to manually do it. It's not a perfect solution, because opening up rails c brings up several lines of initialization code

ETHON: Libcurl initialized
ETHON: performed EASY effective_url=http://localhost:7474/db/data/schema/constraint response_code=200 return_code=ok total_time=0.071625
ETHON: performed EASY effective_url=http://localhost:7474/db/data/schema/index response_code=200 return_code=ok total_time=0.098502
ETHON: performed EASY effective_url=http://localhost:7474/db/data/transaction/commit response_code=200 return_code=ok total_time=0.7863

Now, while writing up this comment I realized that, when generating my project, I failed to omit ActiveRecord with the -O flag. Neo4jrb is suppose to work fine alongside ActiveRecord according to the docs, but I decided to test generating the same project except without ActiveRecord using

rails new issue-test -m http://neo4jrb.io/neo4j/neo4j.rb -B -O
rake neo4j:install[community-3.1.4]

In this scenerio, everything works normally. I imagine its not super common for someone to use Neo4j alongside ActiveRecord, so maybe this is a regression that was introduced at some point? Regardless, @kroyagis, does your project have ActiveRecord in it? If so, do you need it? You might be able to easily resolve the issue by removing ActiveRecord. To do so edit your application.rb file so that instead of require rails/rails it has

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
# require "active_record/railtie"
require 'neo4j/railtie'
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie"
require "rails/test_unit/railtie"

@cheerfulstoic, this test was created with the following Vagrantfile. This test works if the project is generated with rails new issue-test -m http://neo4jrb.io/neo4j/neo4j.rb -B -O. It does not work if the project was generated with rails new issue-test -m http://neo4jrb.io/neo4j/neo4j.rb -B.

# Project Generated with
# rails new issue-test -m http://neo4jrb.io/neo4j/neo4j.rb -B -O

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://atlas.hashicorp.com/search.
  config.vm.box = "ubuntu/xenial64"

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  config.vm.network "forwarded_port", guest: 3000, host: 3800, host_ip: "127.0.0.1"
  config.vm.network "forwarded_port", guest: 7474, host: 7474, host_ip: "127.0.0.1"
  config.vm.network "forwarded_port", guest: 7473, host: 7473, host_ip: "127.0.0.1"
  config.vm.network "forwarded_port", guest: 7472, host: 7472, host_ip: "127.0.0.1"
  config.vm.network "forwarded_port", guest: 7574, host: 7574, host_ip: "127.0.0.1"
  config.vm.network "forwarded_port", guest: 7573, host: 7573, host_ip: "127.0.0.1"
  config.vm.network "forwarded_port", guest: 7572, host: 7572, host_ip: "127.0.0.1"

  # Share an additional folder to the guest VM or configure . The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.

  project_name = "issue-test"
  raise if project_name.nil? || project_name == ""

  config.vm.synced_folder ".", "/home/ubuntu/#{project_name}"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Disable notify-forwarder plugin, if present, because it was messing with Neo4j and causing a database panic
  # https://discuss.elastic.co/t/es-cluster-in-docker-containers-alreadyclosedexception-underlying-file-changed-by-an-external-force/48874/8
  if Vagrant.has_plugin?("vagrant-notify-forwarder")
    config.notify_forwarder.enable = false
  end

  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.

  config.vm.provision "bootstrapping", type: "shell", privileged: false,
    keep_color: true, inline: <<-SHELL
      PURPLE='\033[1;35m'; GREEN='\033[1;32m'; NC='\033[0;0m'
      echo "${PURPLE}BEGINNING BOOTSTRAPPING PROCESS...Grab a drink. This could take a while.${NC}"
      echo ' '
      echo "${PURPLE}UPDATING .BASHRC FILE${NC}"
      echo "export ROOT_URL='http://localhost:3000'" >> /home/ubuntu/.bashrc
      echo "cd /home/ubuntu/#{project_name}" >> /home/ubuntu/.bashrc
      cd ~/#{project_name}
      echo "${GREEN}COMPLETED UPDATING .BASHRC FILE${NC}"
      echo ' '
      echo "${PURPLE}INSTALLING JAVA${NC}"
      # Updates apt-get to point to updated java8 package
      yes | sudo add-apt-repository ppa:webupd8team/java
      # Updates apt-get
      sudo apt-get update
      # Set debconf config file to mark java8 license prompts as completed
      # https://askubuntu.com/questions/190582/installing-java-automatically-with-silent-option#
      # Install java8 without prompts
      echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections
      echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections
      yes | sudo apt-get install oracle-java8-installer
      echo "${GREEN}COMPLETED INSTALLING JAVA${NC}"
      echo ' '
      echo "${PURPLE}INSTALLING RVM & RUBY${NC}"
      yes | sudo apt-get install gnupg2
      gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
      # Current issue with rvm: https://github.com/rvm/rvm/issues/4068
      # use this patch until fixed
      curl -sSL https://raw.githubusercontent.com/wayneeseguin/rvm/stable/binscripts/rvm-installer | bash -s stable --ruby=2.4
      # curl -sSL https://get.rvm.io | bash -s stable --ruby=2.4
      source /home/ubuntu/.rvm/scripts/rvm
      echo "${GREEN}COMPLETED INSTALLING RVM & RUBY${NC}"
      echo ' '
      echo "${PURPLE}INSTALLING GEMS${NC}"
      gem install bundler --no-rdoc --no-ri
      # also install libcurl3, libcurl3-gnutls, & libcurl4-openssl-dev
      # which are needed by the "curb" gem, used in some 3rd party rake tasks
      yes | sudo apt-get install libcurl3 libcurl4-openssl-dev #libcurl3-gnutls
      bundle install
      echo "${GREEN}COMPLETED INSTALLING GEMS${NC}"
  SHELL

  config.vm.provision "bootstrapping complete", type: "shell", privileged: false,
    keep_color: true, run: "always", inline: <<-SHELL
      GREEN="\033[1;32m"; BLUE='\033[1;34m'; NC="\033[0;0m"
      echo "${GREEN}BOOTSTRAPPING COMPLETE!${NC}"
      echo "${BLUE}Database and app server not started${NC}"
      echo ' '
      echo "${BLUE}To connect to the app server in your browser visit:${NC}"
      echo "${BLUE}- HTTP: http://localhost:3000${NC}"
      echo It may take a minute or two for the servers to boot up...
    SHELL
end
cheerfulstoic commented 6 years ago

Oh ho! Very good catch! I tried this and found that the problem is that require 'neo4j/railtie' isn't being added to the top of the config/application.rb. That is the thing that triggers the railtie.

The code to make this happen is in the gh-pages branch of the neo4j gem:

https://github.com/neo4jrb/neo4j/blob/gh-pages/neo4j.rb

That's what allows us to have the http://neo4jrb.io/neo4j/neo4j.rb URL for the -m flag.

That script adds require 'neo4j/railtie' after require "active_record/railtie", but when you don't use the -O flag you end up with require 'rails/all' in the application.rb. With the -O flag you get:

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
# require "active_record/railtie"
require 'neo4j/railtie'
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie"
require "rails/test_unit/railtie"

So I've just added the following line to the setup script which seems to fix it:

inject_into_file 'config/application.rb', "\nrequire 'neo4j/railtie'", after: "require 'rails/all'"
jorroll commented 6 years ago

@cheerfulstoic nice 👍 !

jorroll commented 6 years ago

Just tested, and I can confirm that this fixes the issue I was experiencing.

benjaminbradley commented 6 years ago

I'm running into this issue after having upgraded from neo4j 7.1.2 to 8.2.3

calling code is in a Rails rake task: neo4j_transaction = Neo4j::Transaction.new

This syntax is based on the documentation at https://github.com/neo4jrb/neo4j-core/wiki/Transaction

I know that the Neo4j session has already been established by looking at my logs, up to this point the rake task has successfully been reading records from the Neo4j database via the ActiveNode models.

It looks like the method being called has a default argument of Session.current! per the rubydoc at: http://www.rubydoc.info/github/neo4jrb/neo4j-core/Neo4j%2FTransaction:new

The upgrade guid does mention a change to how to access the current session: http://neo4jrb.readthedocs.io/en/8.2.x/UpgradeGuide.html#sessions

So following that pattern, I was able to fix the issue by passing in the current session as: neo4j_transaction = Neo4j::Transaction.new(Neo4j::ActiveBase.current_session)

Transactions are not mentioned in the upgrade guide at: http://neo4jrb.readthedocs.io/en/8.2.x/UpgradeGuide.html

Transaction handling is also not mentioned (except in the context of Migrations) in the new docs at http://neo4jrb.readthedocs.io/en/8.2.x/

It seems like this is either a bug in the default parameter of Neo4j::Transaction:new() or a documentation issue, I'm not sure which.

cheerfulstoic commented 6 years ago

Hey @benjaminbradley !

Good point, I think there were some things that changed that weren't documented. Another thing that you might try is using:

Neo4j::ActiveBase.run_transaction do
  # <code>
end
# or
tx = Neo4j::ActiveBase.new_transaction

That should do transactions and use the current ActiveBase session in the process.

Somebody pointed out recently that ActiveBase isn't documented, and it's become a place where some central things live. So if that works for you we can make documenting that a priority.

jorroll commented 6 years ago

also

Neo4j::ActiveBase.run_transaction do |tx|
  tx.mark_failed
end
whatbird commented 6 years ago

i was having the above session missing issue with Neo4j::Transaction (and other bare metal Neo4j commands) even though the "normal" Neo4j::ActiveNode functionality (ie: Item.create()) was working/configured correctly.

i switched to the ActiveBase style transactions (per @thefliik and @cheerfulstoic), and that cleared up the session error message. but transactions don't seem to rollback. (oops, can no longer reproduce)

cheerfulstoic commented 6 years ago

Hey @whatbird ! Thanks for letting us know about this. Could you perhaps provide some simple example code that we can test?