Runs a program that speaks the beamports --jsonl request protocol as an
Erlang port, and sends it one request at a time.
The protocol is one JSON object per line in each direction: a request
{"version":1,"request_id":N,"operation":"...","payload":{...}} and a
reply with the same request_id and either "ok":true,"data":... or
"ok":false,"error":"...". duckport, oxiport and tantiport speak it when
started with --jsonl.
Each JsonlPort process owns one program, started on the first request
and restarted on the next request after it exits. Requests are serialised:
a request waits until the one before it has been answered.
A request that gets no valid reply in time ends with an error, and the
program is killed before the next request starts. A write that the
program finishes later therefore cannot overlap the next request, but it
may still have happened: the caller has to treat
{:error, :uncertain_native_outcome} as unknown, not as failed.
{:ok, pid} =
JsonlPort.start_link(
executable: "/usr/local/bin/duckport",
args: ["--jsonl", "--database", "/var/db/app/analytics.duckdb"]
)
{:ok, %{"rows" => [%{"answer" => 42}]}} =
JsonlPort.request(pid, "query", %{sql: "SELECT 42 AS answer", params: []})
Summary
Functions
Returns a specification to start this module under a supervisor.
Sends one request and waits up to timeout milliseconds for its reply.
Kills the program, if it is running, once the request in progress (if any) has been answered. The next request starts it again.
Starts a process for one program. The program itself starts with the first request.
Types
@type error() :: :missing_executable | :packet_limit | :invalid_protocol | :uncertain_native_outcome | {:native_exit, term()} | String.t()
Why a request failed.
:missing_executable-:executableis not a regular file.:packet_limit- the request or the reply is larger than 16 MiB.:invalid_protocol- the reply is not JSON, has another version, or answers another request.:uncertain_native_outcome- no reply before the timeout; the program was killed, and the request may or may not have taken effect.{:native_exit, status}- the program exited before replying.- a binary - the program's own error, from
"ok":false; or the message of an exception raised while handling the request.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec request(GenServer.server(), String.t(), term(), timeout()) :: {:ok, term()} | {:error, error()}
Sends one request and waits up to timeout milliseconds for its reply.
payload is encoded with Jason. Returns {:ok, data} with the reply's
decoded data, or {:error, reason} (see error/0).
@spec reset(GenServer.server(), timeout()) :: :ok
Kills the program, if it is running, once the request in progress (if any) has been answered. The next request starts it again.
@spec start_link(keyword()) :: GenServer.on_start()
Starts a process for one program. The program itself starts with the first request.
Options:
:executable- absolute path of the program (required).:args- its arguments, for example["--jsonl", "--index", path].:name- registers the process, as inGenServer.start_link/3.