elixir-concurrency

Elixir concurrency patterns: Tasks, GenStage pipelines, Broadway data ingestion, Flow parallel processing, Oban background jobs. Use when building concurrent or parallel data processing systems.

Best use case

elixir-concurrency is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Elixir concurrency patterns: Tasks, GenStage pipelines, Broadway data ingestion, Flow parallel processing, Oban background jobs. Use when building concurrent or parallel data processing systems.

Teams using elixir-concurrency should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/elixir-concurrency/SKILL.md --create-dirs "https://raw.githubusercontent.com/ratnesh-maurya/cursor-claude-personas/main/senior-elixir-developer/.claude/skills/elixir-concurrency/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/elixir-concurrency/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How elixir-concurrency Compares

Feature / Agentelixir-concurrencyStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Elixir concurrency patterns: Tasks, GenStage pipelines, Broadway data ingestion, Flow parallel processing, Oban background jobs. Use when building concurrent or parallel data processing systems.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Elixir Concurrency Patterns

Concurrency and parallel processing patterns for the BEAM VM.

## When to Use

- Running concurrent operations (API calls, file processing)
- Building data ingestion pipelines from message queues
- Parallel processing of large datasets
- Background job processing
- Fan-out/fan-in computation patterns

## Tasks

### Async/Await (Concurrent Computation)

```elixir
task1 = Task.async(fn -> fetch_user_profile(user_id) end)
task2 = Task.async(fn -> fetch_user_orders(user_id) end)
task3 = Task.async(fn -> fetch_user_notifications(user_id) end)

profile = Task.await(task1)
orders = Task.await(task2)
notifications = Task.await(task3)
```

### Async Stream (Parallel with Back-Pressure)

```elixir
urls
|> Task.async_stream(&HTTPClient.get/1, max_concurrency: 10, timeout: 30_000)
|> Enum.map(fn
  {:ok, {:ok, response}} -> response
  {:ok, {:error, reason}} -> {:error, reason}
  {:exit, reason} -> {:error, {:crashed, reason}}
end)
```

### Supervised Tasks (Fault-Isolated)

```elixir
# In supervision tree
{Task.Supervisor, name: MyApp.TaskSupervisor}

# Fire-and-forget (supervised)
Task.Supervisor.start_child(MyApp.TaskSupervisor, fn ->
  send_welcome_email(user)
end)

# Async with isolation (won't crash caller)
task = Task.Supervisor.async_nolink(MyApp.TaskSupervisor, fn ->
  expensive_computation()
end)

case Task.yield(task, 5_000) || Task.shutdown(task) do
  {:ok, result} -> result
  nil -> {:error, :timeout}
end
```

## GenStage (Custom Pipelines)

Demand-driven producer-consumer with built-in back-pressure:

```elixir
# Producer
defmodule MyApp.DataProducer do
  use GenStage

  def init(:ok), do: {:producer, %{}}

  def handle_demand(demand, state) when demand > 0 do
    events = fetch_batch(demand)
    {:noreply, events, state}
  end
end

# Consumer
defmodule MyApp.DataConsumer do
  use GenStage

  def init(:ok) do
    {:consumer, %{}, subscribe_to: [{MyApp.DataProducer, max_demand: 50, min_demand: 10}]}
  end

  def handle_events(events, _from, state) do
    Enum.each(events, &process_event/1)
    {:noreply, [], state}
  end
end
```

## Broadway (Data Ingestion)

High-level pipeline for message queue ingestion:

```elixir
defmodule MyApp.Pipeline do
  use Broadway

  def start_link(_opts) do
    Broadway.start_link(__MODULE__,
      name: __MODULE__,
      producer: [
        module: {BroadwaySQS.Producer, queue_url: System.fetch_env!("SQS_QUEUE_URL")},
        concurrency: 2
      ],
      processors: [
        default: [concurrency: 10]
      ],
      batchers: [
        default: [batch_size: 100, batch_timeout: 1_000, concurrency: 5]
      ]
    )
  end

  @impl true
  def handle_message(_processor, message, _context) do
    message
    |> Broadway.Message.update_data(&Jason.decode!/1)
    |> Broadway.Message.put_batcher(:default)
  end

  @impl true
  def handle_batch(:default, messages, _batch_info, _context) do
    rows = Enum.map(messages, fn msg -> msg.data end)
    MyApp.Repo.insert_all(Event, rows)
    messages
  end
end
```

Broadway supports: SQS, Kafka, RabbitMQ, Google Cloud PubSub out of the box.

## Flow (Parallel Data Processing)

MapReduce-style for large enumerables:

```elixir
# Word frequency count across files
File.ls!("./data")
|> Flow.from_enumerable(max_demand: 5)
|> Flow.flat_map(fn file ->
  File.read!("./data/#{file}")
  |> String.split(~r/\s+/)
  |> Enum.map(&String.downcase/1)
end)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, acc ->
  Map.update(acc, word, 1, &(&1 + 1))
end)
|> Enum.to_list()
```

Flow works in batches of 500 by default — only shows improvement on larger datasets.

## Oban (Background Jobs)

PostgreSQL-backed job queue with ACID guarantees:

```elixir
# Define a worker
defmodule MyApp.Workers.SendEmail do
  use Oban.Worker, queue: :mailers, max_attempts: 3

  @impl true
  def perform(%Oban.Job{args: %{"to" => to, "template" => template}}) do
    case MyApp.Mailer.deliver(to, template) do
      {:ok, _} -> :ok
      {:error, reason} -> {:error, reason}  # Will retry
    end
  end
end

# Enqueue a job
%{to: "user@example.com", template: "welcome"}
|> MyApp.Workers.SendEmail.new()
|> Oban.insert()

# Schedule for later
%{report_id: 123}
|> MyApp.Workers.GenerateReport.new(schedule_in: 3600)
|> Oban.insert()
```

### Oban Configuration

```elixir
config :my_app, Oban,
  repo: MyApp.Repo,
  queues: [
    default: 10,
    mailers: 5,
    critical: 20,
    reports: 3
  ],
  plugins: [
    {Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 7},  # Clean jobs older than 7 days
    {Oban.Plugins.Cron, crontab: [
      {"0 * * * *", MyApp.Workers.HourlySync},
      {"0 0 * * *", MyApp.Workers.DailyReport}
    ]}
  ]
```

### Key Rules

- Keep job args small: pass IDs, not full records
- Design workers to be **idempotent** (safe for retries)
- Use `Oban.Testing` for test assertions

## Choosing the Right Tool

| Need | Tool |
|------|------|
| 2-10 concurrent operations | `Task.async/await` |
| Process a list in parallel | `Task.async_stream` |
| Fire-and-forget background work | `Task.Supervisor.start_child` |
| Custom producer-consumer pipeline | `GenStage` |
| Message queue ingestion (SQS/Kafka) | `Broadway` |
| Parallel data crunching | `Flow` |
| Reliable background jobs with retries | `Oban` |
| Scheduled/cron jobs | `Oban` with Cron plugin |

## Anti-Patterns

- **Processes for code organization**: Processes model runtime concerns, not code structure
- **Unbounded spawning**: Always use supervisors; prefer `Task.Supervisor` over raw `Task.async`
- **Ignoring back-pressure**: Raw message passing can overflow mailboxes; use GenStage/Broadway
- **Large Oban payloads**: Pass IDs, not data blobs
- **Non-idempotent workers**: Jobs may retry; design for safe re-execution
- **`Task.async` without `await`/`yield`**: Linked tasks crash the caller on failure

## Key Libraries

- `Task`, `Task.Supervisor` (stdlib)
- `GenStage`, `Flow` (Dashbit)
- `Broadway` + producers: `broadway_sqs`, `broadway_kafka`, `broadway_rabbitmq`
- `Oban` (background jobs), `Oban.Pro` (workflows, batch jobs, Web UI)

Related Skills

go-concurrency-patterns

5
from ratnesh-maurya/cursor-claude-personas

Master Go concurrency with goroutines, channels, sync primitives, and context. Use when building concurrent Go applications, implementing worker pools, or debugging race conditions.

elixir-testing

5
from ratnesh-maurya/cursor-claude-personas

Elixir testing patterns: ExUnit, Mox behaviour-based mocking, StreamData property testing, Phoenix integration tests. Use when writing tests for Elixir/Phoenix applications.

elixir-pro

5
from ratnesh-maurya/cursor-claude-personas

Write idiomatic Elixir code with OTP patterns, supervision trees, and Phoenix LiveView. Masters concurrency, fault tolerance, and distributed systems.

elixir-otp-patterns

5
from ratnesh-maurya/cursor-claude-personas

OTP architecture patterns for Elixir: GenServer, Supervisor, DynamicSupervisor, Registry, Application. Use when designing fault-tolerant process architectures, supervision trees, or stateful services.

elixir-deployment

5
from ratnesh-maurya/cursor-claude-personas

Elixir deployment patterns: Mix releases, Docker multi-stage builds, clustering with libcluster, runtime config, health checks, observability. Use when deploying Elixir/Phoenix to production.

wordpress-penetration-testing

5
from ratnesh-maurya/cursor-claude-personas

This skill should be used when the user asks to "pentest WordPress sites", "scan WordPress for vulnerabilities", "enumerate WordPress users, themes, or plugins", "exploit WordPress vu...

php-pro

5
from ratnesh-maurya/cursor-claude-personas

Write idiomatic PHP code with generators, iterators, SPL data structures, and modern OOP features. Use PROACTIVELY for high-performance PHP applications.

moodle-external-api-development

5
from ratnesh-maurya/cursor-claude-personas

Create custom external web service APIs for Moodle LMS. Use when implementing web services for course management, user tracking, quiz operations, or custom plugin functionality. Covers parameter va...

laravel-expert

5
from ratnesh-maurya/cursor-claude-personas

Senior Laravel Engineer role for production-grade, maintainable, and idiomatic Laravel solutions. Focuses on clean architecture, security, performance, and modern standards (Laravel 10/11+).

voice-ai-engine-development

5
from ratnesh-maurya/cursor-claude-personas

Build real-time conversational AI voice engines using async worker pipelines, streaming transcription, LLM agents, and TTS synthesis with interrupt handling and multi-provider support

voice-ai-development

5
from ratnesh-maurya/cursor-claude-personas

Expert in building voice AI applications - from real-time voice agents to voice-enabled apps. Covers OpenAI Realtime API, Vapi for voice agents, Deepgram for transcription, ElevenLabs for synthesis...

voice-agents

5
from ratnesh-maurya/cursor-claude-personas

Voice agents represent the frontier of AI interaction - humans speaking naturally with AI systems. The challenge isn't just speech recognition and synthesis, it's achieving natural conversation flo...