Context in Elixir

Here’s the translation of the Go code to Elixir, with explanations in Markdown format suitable for Hugo:

In this example, we’ll look at setting up a simple HTTP server. HTTP servers are useful for demonstrating the usage of processes for controlling cancellation. In Elixir, we use processes and message passing to handle concurrency and cancellation, which is similar to the concept of context.Context in other languages.

defmodule Context do
  use Application

  def start(_type, _args) do
    children = [
      {Plug.Cowboy, scheme: :http, plug: Context.Router, options: [port: 8090]}
    ]
    opts = [strategy: :one_for_one, name: Context.Supervisor]

    Supervisor.start_link(children, opts)
  end
end

defmodule Context.Router do
  use Plug.Router

  plug :match
  plug :dispatch

  get "/hello" do
    IO.puts("server: hello handler started")

    task = Task.async(fn ->
      :timer.sleep(10000)
      send(self(), :done)
    end)

    receive do
      :done ->
        send_resp(conn, 200, "hello\n")
      {:EXIT, _pid, reason} ->
        IO.puts("server: #{inspect(reason)}")
        send_resp(conn, 500, "Internal Server Error")
    after
      11000 ->
        Task.shutdown(task)
        send_resp(conn, 500, "Request timed out")
    end

    IO.puts("server: hello handler ended")
  end

  match _ do
    send_resp(conn, 404, "Not found")
  end
end

In this Elixir code:

  1. We define an Application module that starts a Cowboy server with our Router module.

  2. In the Router module, we define a /hello route that simulates a long-running operation.

  3. We use Task.async to start a process that sleeps for 10 seconds, simulating work.

  4. We use receive to wait for either the task to complete or an exit signal.

  5. If the task completes, we send a success response. If we receive an exit signal (simulating cancellation), we send an error response.

  6. We also have a timeout of 11 seconds, after which we shut down the task and send a timeout response.

To run the server:

$ mix run --no-halt

To simulate a client request to /hello, hitting Ctrl+C shortly after starting to signal cancellation:

$ curl localhost:8090/hello
server: hello handler started
^C
server: :shutdown
server: hello handler ended

This example demonstrates how Elixir handles concurrent operations and cancellation using processes and message passing, which is conceptually similar to using contexts for cancellation in other languages.