group_registry
Groups that can be joined and left by processes, and the members of which can be listed on request. This may be useful for publish-subscribe patterns, where many processes want to receive messages another.
This module is implemented using Erlang’s pg
module and uses ETS
for storage, so listing the members of a group is optimised for speed.
Groups are tracked by group registry processes, which you should add to your supervision tree. Each registry is independant from each other.
If a member terminates, it is automatically removed from the group.
If a group registry terminates the groups are lost and will need to be recreated. Restarting the group registry will not recover the groups.
There is no memory cost to the registry of a group without any members.
Publish-subscribe
This module is useful for pubsub, but it does not offer any functions for
sending messages itself. To perform pubsub add the subscriber messages to
a group, then the publishers can use the members
function to get a
list of subjects for the subscribers and send messages to them.
Distributed groups
If two nodes in an Erlang cluster have process registries or pg
instances created with the same name (called a “scope” in the pg
documentation) they will share group membership in an eventually
consistent way. See the pg
documentation for more information. Note that
names created with the process.new_name
are unique, so calling that
function with the same prefix string on each node in an Erlang cluster
will result in distinct names.
Scalability
Inserting members or getting all the members of a group pg
is fast, but
removing members from large groups with thousands of members in them is
much slower. This module is best suited to numerous small groups.
If you need larger groups and members to be removed or to terminate frequently you may want to experiment with other registries. Always benchmark and profile your code when performance matters.
Types
A reference to the group registry process.
The type parameter is a message type that processes registered with the registry can be sent.
pub type GroupRegistry(message)
The message type that the registry accepts. This type is opaque and cannot be constructed directly. Instead use the functions in this module to interact with the registry.
The type parameter is a message type that processes registered with the registry can be sent.
pub type Message(message)
Values
pub fn get_registry(
name: process.Name(Message(message)),
) -> GroupRegistry(message)
pub fn join(
registry: GroupRegistry(message),
group: String,
new_member: process.Pid,
) -> process.Subject(message)
Add a process to a group.
A process can join a group many times and must then leave the group the same number of times.
A subject is returned which can be used to send to messages to the member, or for the member to receive messages.
pub fn leave(
registry: GroupRegistry(message),
group: String,
members: List(process.Pid),
) -> Nil
Remove the given processes from the group, if they are members.
pub fn members(
registry: GroupRegistry(message),
group: String,
) -> List(process.Subject(message))
Returns subjects for all processes in the group. They are returned in no specific order.
If a process joined the group multiple times it will be present in the list that number of times.
pub fn start(
name: process.Name(Message(message)),
) -> Result(
actor.Started(GroupRegistry(message)),
actor.StartError,
)
Start the registry with the given name. You likely want to use the
supervised
function instead, to add the registry to your supervision
tree, but this may still be useful in your tests.
Remember that names must be created at the start of your program, and must not be created dynamically such as within your supervision tree (it may restart, creating new names) or in a loop.
pub fn supervised(
name: process.Name(Message(message)),
) -> supervision.ChildSpecification(GroupRegistry(message))
A specification for starting the registry under a supervisor, using the given name. You should likely use this function in applications.
Remember that names must be created at the start of your program, and must not be created dynamically such as within your supervision tree (it may restart, creating new names) or in a loop.