florinpatrascu / bolt_sips

Neo4j driver for Elixir
Apache License 2.0
256 stars 49 forks source link

Config field for `timeout` not reflected in query timeouts #100

Closed ThunderHeavyIndustries closed 3 years ago

ThunderHeavyIndustries commented 3 years ago

Environment

Current behavior

When setup with:

# inside config/dev.ex
config :bolt_sips, Bolt,
  url: "bolt://localhost:7687",
  basic_auth: [username: "*****", password: "****"],
  timeout: 30_000,
  pool_size: 40

Running a somewhat long query (which is verified to work in the Neo4j desktop client) I'm getting timeout errors:

[error] Bolt.Sips.Protocol (#PID<0.12378.0>) disconnected: ** (DBConnection.ConnectionError) client #PID<0.12385.0> timed out because it queued and checked out the connection for longer than 15000ms

Expected behavior

Changing the value in the timeout field in the configuration fails to be reflected in queries. I've tried setting the timeout to lower and higher than 15_000 and I still get errors with for longer than 15000ms regardless of what the timeout is set to in the config.

Thanks for your help!

florinpatrascu commented 3 years ago

@ThunderHeavyIndustries - can you please use the latest published release and let us know if the problem is fixed?! Thank you

ThunderHeavyIndustries commented 3 years ago

Sure thing, I'll give it a go next week and get back to you.

ThunderHeavyIndustries commented 3 years ago

Thanks for getting back to me on this! I'm still experiencing the same issue/seeing the same 1500 ms response after updating to 2.0.10.

Maybe there's something on my end? Setup is as above. The function calls look like this:

given a query which is a string (again verified to work in the Neo4j Desktop client)

  def conn() do
    Bolt.Sips.conn()
  end

  def execute(query) do
    Bolt.Sips.transaction(conn(), fn con ->
      Bolt.Sips.query!(con, query)
    end)
  end

I also tried passing the timeout as part of the params

  def execute(query) do
    Bolt.Sips.transaction(conn(), fn con ->
      Bolt.Sips.query!(con, query, %{}, timeout: 60_000)
    end)
  end

Which doesn't change the behavior or the error message either. Thanks again for your help on this!

florinpatrascu commented 3 years ago

yeah I am sorry, it was my fault. It should work now with 2.0.11.

Here's one easy way to test, provided you have the APOC enabled:

{:ok, _neo} = Sips.start_link(url: "bolt://neo4j:test@localhost")
conn = Sips.conn()

Sips.query(conn, "CALL apoc.util.sleep(30000) RETURN 1 as test", %{}, timeout: 35_000)

HTH

ThunderHeavyIndustries commented 3 years ago

ah cool ok I'll test it on monday, thanks again!

ThunderHeavyIndustries commented 3 years ago

SO SORRY! Crazy week I'll be checking it out later today!

florinpatrascu commented 3 years ago

No worries, please take your time :)) many thanks

ThunderHeavyIndustries commented 3 years ago

Yes indeed updating does seem to respect the timeout when the query is run as presented, with one caveat!

This still seems to be dying with the longer than 15000ms error message when passed as such:

  def execute(query) do
    Bolt.Sips.transaction(conn(), fn con ->
      Bolt.Sips.query!(con, query)
    end)
  end

or


  def execute(query) do
    Bolt.Sips.transaction(conn(), fn con ->
      Bolt.Sips.query!(con, query, %{}, timeout: 30_000)
    end)
  end

but this does respect the timeout whether set from the config, or passed in the params

  def execute(query) do
      # :timeout set in config
      Bolt.Sips.query!(conn(), query, %{})
  end

or

  def execute(query) do
    Bolt.Sips.query!(conn(), query, %{}, timeout: 30_000)
  end
florinpatrascu commented 3 years ago

Oh that's interesting, thank you for such a thorough investigation and for the examples. I'm going to look into the transaction next, in case it is related, and will report back my findings. Many thanks again!

florinpatrascu commented 3 years ago

I see what is going on. When you wrap your queries in transactions, Bolt.Sips delegates the call to the underlining library: DBConnection, including your custom ... options ;)

Please try this instead:

  def execute(query) do
    Bolt.Sips.transaction(conn(), fn con ->
      Bolt.Sips.query!(con, query)
    end, timeout: 30_000)
  end
ThunderHeavyIndustries commented 3 years ago

I'll give that a go tomorrow!

florinpatrascu commented 3 years ago

please reopen, in case you find any other related issue. Thanks again!