README.md

# GlobalSemaphore

[![CI](https://github.com/devall-org/global_semaphore/actions/workflows/ci.yml/badge.svg)](https://github.com/devall-org/global_semaphore/actions/workflows/ci.yml)

Cluster-wide semaphore with a dead-simple API.

```elixir
# config :global_semaphore, :limits, pdf_api: 3

GlobalSemaphore.with_permit(:pdf_api, fn ->
  generate_pdf()  # max 3 concurrent calls across the entire cluster
end)
```

## Why?

- **Cluster-wide**: Works across all nodes, not just one
- **Simple**: One config line, one function call. No complex concepts.
- **No dependencies**: Uses Erlang's built-in `:global` module

## Installation

```elixir
def deps do
  [{:global_semaphore, "~> 0.1.0"}]
end
```

## Usage

```elixir
# config/runtime.exs
config :global_semaphore, :limits,
  pdf_api: 3,
  email_api: 5
```

```elixir
# Recommended: automatic acquire/release
GlobalSemaphore.with_permit(:pdf_api, fn ->
  call_pdf_api()
end)

# Manual control when needed
GlobalSemaphore.acquire(:pdf_api)
try do
  call_pdf_api()
after
  GlobalSemaphore.release(:pdf_api)
end
```

## Limitations

- Uses `:global` which has known issues during network partitions (rare in practice)
- If the node hosting the semaphore dies, queued requests fail (next request auto-recovers)

## License

MIT