HTTP.AbortController (http_fetch v0.8.0)

Request cancellation mechanism similar to the browser's AbortController API.

This module provides a way to abort in-flight HTTP requests using an Agent-based controller. It's designed to work with the HTTP.fetch/2 function via the :signal option.

How It Works

  1. Create an AbortController before making the request
  2. Pass the controller to HTTP.fetch/2 via the :signal option
  3. Call abort/1 on the controller to cancel the request
  4. The awaiting Promise will receive an error result

Basic Usage

# Create a controller
controller = HTTP.AbortController.new()

# Start a long-running request with the controller
promise = HTTP.fetch("https://httpbin.org/delay/10",
  signal: controller,
  options: [timeout: 20_000]
)

# Abort the request (e.g., after 2 seconds)
:timer.sleep(2000)
HTTP.AbortController.abort(controller)

# The awaited promise will return an error
case HTTP.Promise.await(promise) do
  {:error, reason} ->
    IO.puts("Request was aborted: " <> inspect(reason))
  response ->
    IO.puts("Request completed before abort")
end

Advanced Usage

# Abort from another process
controller = HTTP.AbortController.new()

# Start request in background
Task.start(fn ->
  promise = HTTP.fetch("https://slow-api.example.com", signal: controller)
  result = HTTP.Promise.await(promise)
  IO.inspect(result)
end)

# Abort from main process after some condition
:timer.sleep(1000)
if some_condition?() do
  HTTP.AbortController.abort(controller)
end

Implementation Details

  • Uses Elixir's Agent for state management
  • Registers with a Registry for process tracking
  • Calls :httpc.cancel_request/1 internally to abort the request
  • Thread-safe and can be called from any process
  • Idempotent - calling abort/1 multiple times is safe

State Management

The controller maintains the following state:

  • request_id - PID of the active :httpc request (set automatically)
  • signal_ref - Unique reference for registry lookup
  • aborted - Boolean flag indicating abort status

Summary

Functions

Aborts the associated HTTP request. Sends a stop signal to :httpc if a request is active and not already aborted.

Checks if the controller has been aborted.

Returns a specification to start this module under a supervisor.

Creates a new AbortController instance. Returns the PID of the agent, which acts as the controller reference.

Sets the :httpc request_id for the given controller. This links the controller to an active request.

Starts a new AbortController agent. Returns {:ok, pid} of the agent.

Types

state()

@type state() :: %{
  request_id: pid() | nil,
  signal_ref: reference(),
  aborted: boolean()
}

Functions

abort(controller_pid)

@spec abort(pid()) :: :ok

Aborts the associated HTTP request. Sends a stop signal to :httpc if a request is active and not already aborted.

aborted?(controller_pid)

@spec aborted?(pid()) :: boolean()

Checks if the controller has been aborted.

child_spec(arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

new()

@spec new() :: pid()

Creates a new AbortController instance. Returns the PID of the agent, which acts as the controller reference.

set_request_id(controller_pid, request_id)

@spec set_request_id(pid(), pid()) :: :ok

Sets the :httpc request_id for the given controller. This links the controller to an active request.

start_link(initial_state \\ %{request_id: nil, signal_ref: make_ref(), aborted: false})

@spec start_link(state()) :: {:ok, pid()}

Starts a new AbortController agent. Returns {:ok, pid} of the agent.