-
Notifications
You must be signed in to change notification settings - Fork 99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error when used in transactions #129
Comments
What version of Dataloader / Ecto are you using? |
Tried with
|
Interesting. Dataloader.Ecto explicitly sets the caller value to the pid that calls |
Turns out it just expects an Ecto.Multi.new()
|> Ecto.Multi.run(:whatever, fn _, _ ->
loader =
Dataloader.new()
|> Dataloader.add_source(:repo, Dataloader.Ecto.new(MyApp.Repo))
|> Dataloader.load(:repo, :roles, user)
|> Dataloader.run()
{:ok, loader}
end)
|> Ev2.Repo.transaction() Thanks a lot for your time and help! 🙏 Closing this issue.. |
We ran into issues again, now with a correct return value for
Grateful for any hints or pointers! 🙏 |
@benwilson512 not sure if you've seen I re-opened this. I tried to fix it, but didn't get very far in my attempts. Can you confirm that it's an issue in |
@arnodirlam are you able to create an example I can run? |
@benwilson512 Yes, the tests in the linked PR should fail: #130 |
I'm seeing something similar when using a transaction. As far as I can tell, the issue is:
|
@arnodirlam I created #134 to solve my issue with |
Thanks a lot for confirming the issue and for coming up with a PR, @giddie 🙏 I've done more research, and found out the following: Why does dataloader use async processes?Partly for error handling, partly for performance optimization. The hierarchy of processes looks as follows:
Spawning 2. and 4. is for catching errors raised while loading sources and batches, respectively. They trap exits (docs). Why doesn't that work with transactions?A transaction is bound to a DB connection that's held by the process calling Dataloader. DB connections, however, cannot be shared between processes.
-- José Valim on Ecto mailing list (Mar 13, 2017) How does Ecto itself handle this?Ecto's preloader checks whether the process it's called from already has a checked out connection. If yes, it does not preload in parallel (using if match?([_,_|_], preloaders) and not checked_out?(repo_name) and
Keyword.get(opts, :in_parallel, true) do
preloaders
|> Task.async_stream(&(&1.(opts)), timeout: :infinity)
|> Enum.map(fn {:ok, assoc} -> assoc end)
else
Enum.map(preloaders, &(&1.(opts)))
end -- shortened version of the code in Ecto.Repo.Preloader introduced by José Valim in 78ba871 How to fix the issue?By restructuring Dataloader to not spawn processes if it's run from within a transaction. Instead of using In particular, I suggest the following changes (will update according to feedback):
I know it's quite a bit of refactoring, but I think it's worth it! Looking forward to feedback and discussion! @giddie @benwilson512 😄 |
Also @seddy who worked on the async parts a lot 👌 |
Don't think you meant me @arnodirlam, though I'm more than happy to take credit for someone else's work obviously 😹 EDIT: Unless you're referring to this thing I did ages ago and had completely forgotten about 😅 #41 |
Great work @arnodirlam. Looks like you went a few steps further than me by delving into Ecto to find a better solution and writing it all up :) Your recommendations sound good to me. |
Handled now in 1.0.11. To use, make sure that when you call
This will be handled automatically in 2.0 |
Hi there,
we're using Dataloader without Absinthe and came across this error:
when running the following code in a test:
Outside of an
Ecto.Multi
, it works:Is this something that can and should be fixed in
Dataloader
?Thanks a lot for this great project! 🙌
The text was updated successfully, but these errors were encountered: