Add Phoenix.PubSub.subscribe_once/3#199
Add Phoenix.PubSub.subscribe_once/3#199nathanl wants to merge 1 commit intophoenixframework:mainfrom
Phoenix.PubSub.subscribe_once/3#199Conversation
| @spec subscribe_once(t, topic, keyword) :: :ok | {:error, term} | ||
| def subscribe_once(pubsub, topic, opts \\ []) | ||
| when is_atom(pubsub) and is_binary(topic) and is_list(opts) do | ||
| subscriptions = Registry.lookup(pubsub, topic) |
There was a problem hiding this comment.
Unfortunately, I believe there is a race condition here. In betwen the Registry lookup and the else path, another process could have subscribed.
The only way this could work is by doing an insert_new operation to :ets
There was a problem hiding this comment.
Since you can only subscribe yourself, it cannot be a race condition. However, because this is a duplicate registry, there is basicaly no cheap way to check if you are already subscribed. If you have a topic with 100k entries, then this function will be very expensive because you are bringing a 100k elements list to memory, which is why we don't provide this functionality, it is basically an anti-pattern. So it is more scalable to guarantee code wise you won't subscribe multiple times. :)
There was a problem hiding this comment.
a topic with 100k entries
Meaning 100k subscribers?
There was a problem hiding this comment.
Given what you said, I'd like to do a followup docs PR to explain why the caller should guard against multiple subscriptions
|
Closing per the above. :) |
Given that the possibility of duplicate subscriptions was already discussed in the docs on
subscribe/3, I assume there's a performance cost to checking for existing subscriptions that callers may not always want to pay. If so, I'd be happy to document that onsubscribe_once/3. But it seems useful to have this function; I'm looking at a use case where the number of subscriptions to a topic won't be large but duplicate messages would be problematic.Currently, any caller who wants to avoid duplicate subscriptions would need to use some kind of workaround, such as:
subscribe/3more than once by tracking subscriptions in their own process state, or by checkingRegistry.lookup/2directly (relying on an implementation detail of PubSub)unsubscribe/2each time before callingsubscribe/3