Skip to content

Latest commit

 

History

History
179 lines (133 loc) · 4.51 KB

POD_PROTOCOL.md

File metadata and controls

179 lines (133 loc) · 4.51 KB

Elixir Pods: Pod Protocol

This protocol is adapted from Babashka Pods. This protocol must be implemented by any Pod Service.

The Pod Client (client) is the Elixir code that connects to the Pod Service (pod).

Exchange of messages between pod client and the pod happens in the bencode format. Bencode is a bare-bones format that only has four types:

  • integers
  • lists
  • dictionaries (maps)
  • byte strings

The recommended library for processing Bencode in Elixir is https://github.com/folz/bento.

Additionally, payloads like args (arguments) or value (a function return value) are encoded in either JSON or Transit JSON (depends on the pod implementation).

Environment

The pod client will set the ELIXIR_POD environment variable to true when starting the pod. This can be used by the service program (pod) to determine whether it should behave as a pod or not.

Operands

Operands must be implemented on each pod. Operands executes without a namespace and arguments. There are three main operands describe, invoke and shutdown.

describe

This operand will return the description of the pod. It's the first operand that will be called after the start of the service by the pod client.

The following is a map with example describe for the demo pod. Note that the final response will be encoded in bencode.

call

%{
  op: "describe",
  id: "018f2732-9ce5-726a-a1b4-acb86c3099c6" # uuidv7
}
|> Bento.encode!()

response

%{
  format: "json",
  id: "018f2732-9ce5-726a-a1b4-acb86c3099c6" # same as the called operation
  namespaces: [
    %{
      name: "pod.example.demo",
      vars: [
        %{
          name: "add",
          meta: %{
            shortdoc: "arithmetic addition of 2 arguments",
            spec: "(a :: int(), b :: int()) :: int()"
          }
      }]
    }
  ]
}
|> Bento.encode!()
  • format: which encoding will used by the payloads and values (json).
  • namespaces: provides the identifier for all commands.
  • name: the name for the namespace.
  • vars: functions that the namespace support. In this example, for calling the function add the client will send pod.example.demo/add.
  • meta: optional information about the functions.

invoke

The invoke operand will execute a function defined in var, and return it's result (async).

call

%{
  op: "invoke",
  id: "018f277a-7ccc-7678-8b8b-10bbc7374c05",
  var: "com.example.pod/add",
  args: [1, 2],
  opts: [] # additional options
}
|> Bento.encode!()

response

The successful response will have status: :ok and a value with the result of the function.

%{
  id: "018f277a-7ccc-7678-8b8b-10bbc7374c05",
  var: "com.example.pod/add",
  value: 3,
  status: :ok
}
|> Bento.encode!()

error response

If the operation was terminated with error, the response will have status: :error, sent to stdout and can be similar to:

%{
  id: "018f277a-7ccc-7678-8b8b-10bbc7374c05",
  var: "com.example.pod/add",
  error: %{
    code: "com.example.pod/errors/403", # can be any value, maybe http codes would be good
    message: "Illegal input",
    data: %{
      input: ["one"], # the params received
      opts: []
    }
  }
  status: :error
}
|> Bento.encode!()

shutdown

The shutdown operand can optionally be included in the pod service. It is called by the pod client when it requires the pod to stop.

The client will kill the pod in two contexts:

  1. When the client stops, all pods will be killed.
  2. When the client receives the shutdown response from the pod.

call

%{
  op: "shutdown",
  id: "018f279a-e1a7-7b7c-a3b5-7e469faa6ee2" # uuidv7
}
|> Bento.encode!()

response

The pod will send the shutdown response payload when is ready to be killed by the process manager, upon receiving this respose the pod client process manager will kill the pod process by its pid.

%{
  id: "018f279a-e1a7-7b7c-a3b5-7e469faa6ee2",
  op: "shutdown",
  status: :ok
}
|> Bento.encode!()

Input and Output

stdin

The pod must read from stdin (in streams) for input.

stdout

The pod must write to stdout for output. stdout will be used for both success and errors (normal operation results).

stderr

For exceptions that the pod triggers if anything unexpected happends.

Permissions

The recommended pod is a single command that will be an executable. (chmod +x).