Cluster-wide semaphore using Erlang's :global module.
Creates a singleton GenServer per name that limits concurrency across all nodes in the cluster. Each semaphore name operates independently, allowing different limits for different resources.
Configuration
config :global_semaphore, :limits,
pdf_api: 3,
email_api: 5,
payment_api: 2Usage
GlobalSemaphore.with_permit(:pdf_api, fn ->
# Only 3 concurrent executions allowed cluster-wide
end)
# Priority (lower number = higher priority, default 5)
GlobalSemaphore.with_permit({:pdf_api, 1}, fn -> ... end) # high
GlobalSemaphore.with_permit({:pdf_api, 5}, fn -> ... end) # normal (default)
GlobalSemaphore.with_permit({:pdf_api, 10}, fn -> ... end) # lowIntrospection
GlobalSemaphore.list_names()
#=> [:pdf_api]
GlobalSemaphore.status(:pdf_api)
#=> %{
# name: :pdf_api,
# max: 3,
# holders: [%{pid: pid, node: :node1, acquired_at: ~U[...]}],
# waiters: [%{pid: pid, node: :node2, priority: 5, enqueued_at: ~U[...]}]
# }
Summary
Functions
Returns a specification to start this module under a supervisor.
Returns the names of all semaphores currently running in the cluster.
Returns the current status of the semaphore with the given name.
Returns the status of all semaphores currently running in the cluster.
Executes the given function with concurrency limit.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec list_names() :: [term()]
Returns the names of all semaphores currently running in the cluster.
@spec status(term()) :: %{name: term(), max: non_neg_integer(), holders: [map()], waiters: [map()]} | nil
Returns the current status of the semaphore with the given name.
Returns nil if no semaphore with that name is running.
Holders are sorted by acquired_at and waiters are in grant order.
@spec status_all() :: [map()]
Returns the status of all semaphores currently running in the cluster.
Executes the given function with concurrency limit.
Acquires a permit, executes the function, then releases. Handles exceptions safely.