Closed eteeselink closed 3 years ago
Hi,
For some reason I was not notified. I'll look into it.
Hi again,
First, thanks for the kind words.
Regarding your problem, it is because there is a special behaviour in iex that prevents the process to actually exit.
If you modify your module to print the pid like that:
defmodule Mutest do
def foo do
Mutex.under(:some_mutex, :key, fn ->
IO.puts "exiting from #{inspect self}"
exit(:hello)
end)
end
end
You can run the same session:
iex(2)> Mutex.start(:some_mutex)
{:ok, #PID<0.251.0>}
iex(3)> self()
#PID<0.235.0>
iex(4)> Mutest.foo
exiting from #PID<0.235.0>
** (exit) :hello
iex:5: anonymous fn/0 in Mutest.foo/0
(mutex 1.2.0) lib/mut.ex:262: Mutex.apply_with_lock/3
iex(4)> self()
#PID<0.235.0>
iex(5)> Mutest.foo()
=> hangs
And you see that the two calls to self()
returns the same pid. The process did not actually exit.
If you run the code in a "normal" process with spawn(fn -> Mutest.foo() end)
, it works as expected.
I added this test to show that the current implementation behaves well when exit/1
is called from the callback.
The mutex process monitors the processes that lock keys, so whenever they exit, their locks are released. This is why I do not catch exits, indeed, by design.
I wouldn't like to add an :exit
clause to the catch
as it should not be needed. Could you provide a simple example (or best, a failing test) of a lock not being released upon exit, that fails even when not called from iex ?
I thought about it and indeed, if you catch the exit outside of the callback then the problem arises, just as in iex. Is that what you do in your app?
I am not sure if mutex should handle this case. On one hand, it should because the under/4 function. On the other hand, exits are special. I will ask on the forums.
Well,
I just replaced the wrapper with that:
defp apply_with_lock(mutex, lock, fun) do
fun.(lock)
after
release(mutex, lock)
end
So it works as intended, even with exits, and without the bookkeeping for rethrowing :)
Hi! First off, thanks for this excellent library.
Mutex.under_all
has saved my ass more than once.Now if I load this module into IEx:
And then call it:
This is a problem when a process crashes without properly throwing. We've seen this happen in practice (though not in mutexed code) when a database pool timed out and a calling process crashed because of it. I'm not a deep enough BEAM guru to understand exactly when something comes a
:throw
and when something is an:exit
, but this was an:exit
☺We found that Mutex had the same problem when we tried to use it to replace another library that froze upon crashing.
If this is indeed considered a bug and not by design, then it might be a matter as simple as adding an
:exit
clause to thiscatch
, but not sure.Also, my compliments on the
mut.ex
filename.