uwiger / gproc

Extended process registry for Erlang
Apache License 2.0
1.07k stars 232 forks source link

Unable to demonitor a monitor that was created with :follow #140

Closed mdillavou closed 7 years ago

mdillavou commented 7 years ago

I have process that is monitoring a key using the :follow flag, so that it will continue to get the :reg messages even after an :unreg. However, at some point, this process will decide it doesn't care anymore, and will ask gproc to demonitor the key, so that it stops receiving message. Unfortunately, this doesn't appear to work.

The below test is using 0.6.1

For example:

# Peek at the ets table which should be empty
iex(1)> :ets.match(:gproc, :'$1')
[]

# Start monitoring a process with the :follow flag
iex(2)> r = :gproc.monitor({:n, :l, :key}, :follow)
#Reference<0.0.1.980>

# Peek at the ets table, we should see the monitor
iex(3)> :ets.match(:gproc, :'$1')                  
[[{{#PID<0.166.0>, :l}}], [{{#PID<0.166.0>, {:n, :l, :key}}, []}],
 [{{{:n, :l, :key}, :n}, [{#PID<0.166.0>, #Reference<0.0.1.980>, :follow}]}]]

# Tell gproc we are no longer interested in monitoring
iex(4)> :gproc.demonitor({:n, :l, :key}, r)  
:ok

# ets should clear things out, but it doesn't!
iex(5)> :ets.match(:gproc, :'$1')          
[[{{#PID<0.166.0>, :l}}], [{{#PID<0.166.0>, {:n, :l, :key}}, []}],
 [{{{:n, :l, :key}, :n}, [{#PID<0.166.0>, #Reference<0.0.1.980>, :follow}]}]]

# create a new task that registers this key
iex(7)> t = Task.async(fn ->
...(7)>   :gproc.reg({:n, :l, :key})
...(7)>   receive do
...(7)>     _ -> :ok
...(7)>   end
...(7)> end)
%Task{owner: #PID<0.166.0>, pid: #PID<0.181.0>, ref: #Reference<0.0.2.371>}
iex(8)> 

# we should NOT receive a registered message, because we asked to stop monitoring
# Unfortunately, we still do
iex(9)> flush()
{:gproc, :registered, #Reference<0.0.1.980>, {:n, :l, :key}}
:ok

# kill the registered process
iex(11)> send t.pid, :die
:die
iex(12)> Task.await(t)
:ok

# Again, we should not receive an :unreg b/c we asked to stop monitoring
# Unfortunately, we still do.
iex(13)> flush()
{:gproc, :unreg, #Reference<0.0.1.980>, {:n, :l, :key}}
uwiger commented 7 years ago

Looking into this. It appears as if the problem lies in the replication: Not all values are propagated properly.

BTW, in a rewrite I'm working on, I found that the notification logic in gproc_dist is badly designed, so I set out to rewrite it completely. Still, I will try to fix this bug.

mdillavou commented 7 years ago

In my case, I am running without gproc_dist enabled, so everything is using local (:l) keys, and I still see this issue.

uwiger commented 7 years ago

I must have squinted and seen a :g instead of an :l. ;-)

The bugs are actually different. I'll see if I can fix both cases.

mdillavou commented 7 years ago

I have tested your pull request and it appears to be working correctly for me.

uwiger commented 7 years ago

Ok, thanks.