NetRunner (NetRunner v1.0.4)

Copy Markdown View Source

Safe OS process execution for Elixir.

Combines NIF-based async I/O with a persistent shepherd binary to guarantee zero zombie processes, even under BEAM SIGKILL.

Quick start

# Simple command execution
{output, 0} = NetRunner.run(~w(echo hello))

# Streaming with input
NetRunner.stream!(~w(cat), input: "hello world")
|> Enum.to_list()
# => ["hello world"]

# Piping data through a command
NetRunner.stream!(~w(wc -c), input: "hello")
|> Enum.join()
# => "       5\n"

Summary

Functions

Runs a command and collects all output.

Like stream!/2 but returns {:ok, stream} or {:error, reason}.

Creates a stream for incremental I/O with the command.

Functions

run(list, opts \\ [])

Runs a command and collects all output.

Returns {output, exit_status} where output is the concatenated stdout.

Options

  • :stderr - :consume (default, captured internally), :redirect (merged with stdout), or :disabled
  • :input - data to write to stdin (binary or enumerable)
  • :timeout - maximum wall-clock time in milliseconds. Sends SIGTERM then SIGKILL on timeout. Returns {:error, :timeout} instead of {output, exit_status}.
  • :max_output_size - maximum bytes to collect from stdout. Kills the process and returns {:error, {:max_output_exceeded, partial_output}} if exceeded.

Examples

{output, 0} = NetRunner.run(~w(echo hello))
{"hello\n", 0} = {output, 0}

{output, 0} = NetRunner.run(~w(cat), input: "from stdin")

{:error, :timeout} = NetRunner.run(~w(sleep 100), timeout: 100)

{:error, {:max_output_exceeded, _partial}} =
  NetRunner.run(["sh", "-c", "yes"], max_output_size: 1000)

stream(list, opts \\ [])

Like stream!/2 but returns {:ok, stream} or {:error, reason}.

stream!(list, opts \\ [])

Creates a stream for incremental I/O with the command.

Returns a Stream that yields stdout binary chunks. Raises on process start failure.

Options

  • :input - data to write to stdin (binary, list, or Stream)
  • :stderr - :consume (default), :redirect, or :disabled

Examples

# Stream through a command
NetRunner.stream!(~w(sort))
|> Enum.to_list()

# With input
NetRunner.stream!(~w(tr a-z A-Z), input: "hello")
|> Enum.join()
# => "HELLO"