erlangbureau / jamdb_oracle

Oracle Database driver for Erlang
MIT License
103 stars 46 forks source link

`:jamdb_oracle_conn` is reading messages not intended for the driver; breaking test flows #178

Open adobley opened 3 months ago

adobley commented 3 months ago

We have been observing some failures in our tests related to the Jamdb.Oracle driver.

[error] Jamdb.Oracle (#PID<0.1313.0>) disconnected: ** (DBConnection.ConnectionError) :function_clause

We were able to narrow down the commit that introduced this behavior to https://github.com/erlangbureau/jamdb_oracle/commit/7edff839de1edb41388deee6435f3557c1bf45fb

When we add debug statements to the :jamdb_oracle_conn code we can see that it is erroring when trying to process a message that it read. This message in our case contains information added to the Process message queue by Plug.Conn for use in the test behaviors. Without the genserver in :jamdb_oracle the :jamdb_oracle_conn is reading any message off the current Process messages. While this seems to be handled OK in our running app, as far as we have seen, it does break testing.

We have a minimal reproduction in this script without the need for all our testing resources. This script just connects to a Oracle and tries to read off of the DUAL table. However, once there is some message on the Process messages it will fail for jambd_oracle versions 0.5.7 and newer.

#!/usr/bin/env elixir
Mix.install([
  {:ecto_sql, "~> 3.10"},
  {:jamdb_oracle, "0.5.7"}
])

username = System.get_env("ORACLE_USERNAME") || "system"
password = System.get_env("ORACLE_PASSWORD") || "oracle"
hostname = System.get_env("ORACLE_HOSTNAME") || "localhost"
port = System.get_env("ORACLE_PORT") || "1521"
database = System.get_env("ORACLE_DATABASE") || "XE"
url = "ecto://#{username}:#{password}@#{hostname}:#{port}/#{database}"

Application.put_env(:foo, Repo, url: url)

defmodule Repo do
  use Ecto.Repo,
    adapter: Ecto.Adapters.Jamdb.Oracle,
    otp_app: :foo
end

defmodule Main do
  import Ecto.Query, warn: false

  def main do
    Supervisor.start_link([Repo], strategy: :one_for_one)
    IO.inspect(Repo.query("SELECT * FROM DUAL"), label: "works")
    send(self(), :foo)
    IO.inspect(Repo.query("SELECT * FROM DUAL"), label: "errors with :function_clause")
  end
end

Main.main()

Is there a way we can prevent the :jamdb_oracle_conn from reading messages that are not intended for it? This behavior is disrupting our ability to test our app.

vstavskyi commented 3 months ago

Can't fix it fast, I'll publish 0.5.10 with pid in jamdb_oracle.ex like before 0.5.7

adobley commented 3 months ago

Thank you! I've got a patch that seems to fix the issue for this reproduction. But I'm fairly new to erlang, so it may not be the right way to address this issue. I'll open a draft PR in case it helps.

vstavskyi commented 3 months ago

Try my commit with flush()

adobley commented 2 months ago

Sorry about the delay! This fell off my radar. This looks like it addresses our issue.

I was worried that flushing would cause information that the Plug was expecting to find would get lost. However in our current end to end tests this doesn't cause us any issues.

Thanks for addressing this so quickly! Really appreciate your help.

I'm happy to close this if this is something you're looking to promote to master.