Pod :code field
This commit is contained in:
parent
5f384d8540
commit
451d5211ed
3 changed files with 55 additions and 26 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8f08cd7bc8f6c89880cbc708b15889c25b32277b
|
Subproject commit 903489fcb5d23fe1ebf4f6e1e321419ed3739268
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 016e20dc52d553049694d7496602dbbccbd6a949
|
Subproject commit 8f16139ab6e73a91aeb5fe97b398b30670e3fc9b
|
||||||
77
doc/pods.md
77
doc/pods.md
|
|
@ -1,7 +1,7 @@
|
||||||
# Pods
|
# Pods
|
||||||
|
|
||||||
Pods are standalone programs that can expose namespaces with vars to
|
Pods are standalone programs that can expose namespaces with vars to babashka or
|
||||||
babashka. Pods can be created independently from babashka. Any program can be
|
a JVM. Pods can be created independently from babashka. Any program can be
|
||||||
invoked as a pod as long as it implements the _pod protocol_. This protocol is
|
invoked as a pod as long as it implements the _pod protocol_. This protocol is
|
||||||
influenced by and built upon battle-tested technologies:
|
influenced by and built upon battle-tested technologies:
|
||||||
|
|
||||||
|
|
@ -36,6 +36,8 @@ _below_ in Polish and Russian. In Romanian it means _bridge_
|
||||||
|
|
||||||
## Implementing your own pod
|
## Implementing your own pod
|
||||||
|
|
||||||
|
We will refer to babashka or the JVM, invoking the pod, as the pod client.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
Beyond the already available pods mentioned above, eductional examples of pods
|
Beyond the already available pods mentioned above, eductional examples of pods
|
||||||
|
|
@ -77,7 +79,7 @@ Pods created by the babashka maintainers use the identifier `babashka`:
|
||||||
|
|
||||||
#### Message and payload format
|
#### Message and payload format
|
||||||
|
|
||||||
Exchange of _messages_ between babashka and the pod happens in the
|
Exchange of _messages_ between pod client and the pod happens in the
|
||||||
[bencode](https://en.wikipedia.org/wiki/Bencode) format. Bencode is a bare-bones
|
[bencode](https://en.wikipedia.org/wiki/Bencode) format. Bencode is a bare-bones
|
||||||
format that only has four types:
|
format that only has four types:
|
||||||
|
|
||||||
|
|
@ -105,12 +107,12 @@ might not be a good EDN library available. So we use bencode as the first
|
||||||
encoding and choose one of multiple richer encodings on top of this. More
|
encoding and choose one of multiple richer encodings on top of this. More
|
||||||
payload formats might be added in the future (e.g. transit).
|
payload formats might be added in the future (e.g. transit).
|
||||||
|
|
||||||
When calling the `babashka.pods/load-pod` function, babashka will start the pod
|
When calling the `babashka.pods/load-pod` function, the pod client will start
|
||||||
and leave the pod running throughout the duration of a babashka script.
|
the pod and leave the pod running throughout the duration of a babashka script.
|
||||||
|
|
||||||
#### describe
|
#### describe
|
||||||
|
|
||||||
The first message that babashka will send to the pod on its stdin is:
|
The first message that the pod client will send to the pod on its stdin is:
|
||||||
|
|
||||||
``` clojure
|
``` clojure
|
||||||
{"op" "describe"}
|
{"op" "describe"}
|
||||||
|
|
@ -137,10 +139,10 @@ In this reply, the pod declares that payloads will be encoded and decoded using
|
||||||
JSON. It also declares that the pod exposes one namespace,
|
JSON. It also declares that the pod exposes one namespace,
|
||||||
`pod.lispyclouds.sqlite` with one var `execute!`.
|
`pod.lispyclouds.sqlite` with one var `execute!`.
|
||||||
|
|
||||||
The pod encodes the above map to bencode and writes it to stdoud. Babashka reads
|
The pod encodes the above map to bencode and writes it to stdoud. The pod client
|
||||||
this message from the pod's stdout.
|
reads this message from the pod's stdout.
|
||||||
|
|
||||||
Upon receiving this message, babashka creates these namespaces and vars.
|
Upon receiving this message, the pod client creates these namespaces and vars.
|
||||||
|
|
||||||
The optional `ops` value communicates which ops the pod supports, beyond
|
The optional `ops` value communicates which ops the pod supports, beyond
|
||||||
`describe` and `invoke`. It is a map of op names to option maps. In the above
|
`describe` and `invoke`. It is a map of op names to option maps. In the above
|
||||||
|
|
@ -148,7 +150,7 @@ example the pod declares that it supports the `shutdown` op. Since the
|
||||||
`shutdown` op does not need any additional options right now, the value is an
|
`shutdown` op does not need any additional options right now, the value is an
|
||||||
empty map.
|
empty map.
|
||||||
|
|
||||||
As a babashka user, you can load the pod with:
|
As a pod user, you can load the pod with:
|
||||||
|
|
||||||
``` clojure
|
``` clojure
|
||||||
(require '[babashka.pods :as pods])
|
(require '[babashka.pods :as pods])
|
||||||
|
|
@ -162,13 +164,13 @@ As a babashka user, you can load the pod with:
|
||||||
|
|
||||||
#### invoke
|
#### invoke
|
||||||
|
|
||||||
When invoking a var that is related to the pod, let's call it a _proxy var_,
|
When invoking a var that is related to the pod, let's call it a _proxy var_, the
|
||||||
babashka reaches out to the pod with the arguments encoded in JSON or EDN. The
|
pod client reaches out to the pod with the arguments encoded in JSON or EDN. The
|
||||||
pod will then respond with a return value encoded in JSON or EDN. Babashka will
|
pod will then respond with a return value encoded in JSON or EDN. The pod client
|
||||||
then decode the return value and present the user with that.
|
will then decode the return value and present the user with that.
|
||||||
|
|
||||||
Example: the user invokes `(sql/execute! "select * from foo")`. Babashka sends
|
Example: the user invokes `(sql/execute! "select * from foo")`. The pod client
|
||||||
this message to the pod:
|
sends this message to the pod:
|
||||||
|
|
||||||
``` clojure
|
``` clojure
|
||||||
{"id" "1d17f8fe-4f70-48bf-b6a9-dc004e52d056"
|
{"id" "1d17f8fe-4f70-48bf-b6a9-dc004e52d056"
|
||||||
|
|
@ -176,7 +178,7 @@ this message to the pod:
|
||||||
"args" "[\"select * from foo\"]"
|
"args" "[\"select * from foo\"]"
|
||||||
```
|
```
|
||||||
|
|
||||||
The `id` is unique identifier generated by babashka which correlates this
|
The `id` is unique identifier generated by the pod client which correlates this
|
||||||
request with a response from the pod.
|
request with a response from the pod.
|
||||||
|
|
||||||
An example response from the pod could look like:
|
An example response from the pod could look like:
|
||||||
|
|
@ -188,22 +190,22 @@ An example response from the pod could look like:
|
||||||
```
|
```
|
||||||
|
|
||||||
Here, the `value` payload is the return value of the function invocation. The
|
Here, the `value` payload is the return value of the function invocation. The
|
||||||
field `status` contains `"done"`. This tells babashka that this is the last
|
field `status` contains `"done"`. This tells the pod client that this is the last
|
||||||
message related to the request with `id` `1d17f8fe-4f70-48bf-b6a9-dc004e52d056`.
|
message related to the request with `id` `1d17f8fe-4f70-48bf-b6a9-dc004e52d056`.
|
||||||
|
|
||||||
Now you know most there is to know about the pod protocol!
|
Now you know most there is to know about the pod protocol!
|
||||||
|
|
||||||
#### shutdown
|
#### shutdown
|
||||||
|
|
||||||
When babashka is about to exit, it sends an `{"op" "shutdown"}` message, if the
|
When the pod client is about to exit, it sends an `{"op" "shutdown"}` message, if the
|
||||||
pod has declared that it supports it in the `describe` response. Then it waits
|
pod has declared that it supports it in the `describe` response. Then it waits
|
||||||
for the pod process to end. This gives the pod a chance to clean up resources
|
for the pod process to end. This gives the pod a chance to clean up resources
|
||||||
before it exits. If the pod does not support the `shutdown` op, the pod process
|
before it exits. If the pod does not support the `shutdown` op, the pod process
|
||||||
is killed by babashka.
|
is killed by the pod client.
|
||||||
|
|
||||||
#### out and err
|
#### out and err
|
||||||
|
|
||||||
Pods may send messages with an `out` and `err` string value. Babashka prints
|
Pods may send messages with an `out` and `err` string value. The Pod Client prints
|
||||||
these messages to `*out*` and `*err*`. Stderr from the pod is redirected to
|
these messages to `*out*` and `*err*`. Stderr from the pod is redirected to
|
||||||
`System/err`.
|
`System/err`.
|
||||||
|
|
||||||
|
|
@ -220,7 +222,7 @@ these messages to `*out*` and `*err*`. Stderr from the pod is redirected to
|
||||||
#### Error handling
|
#### Error handling
|
||||||
|
|
||||||
Responses may contain an `ex-message` string and `ex-data` payload string (JSON
|
Responses may contain an `ex-message` string and `ex-data` payload string (JSON
|
||||||
or EDN) along with an `"error"` value in `status`. This will cause babashka to
|
or EDN) along with an `"error"` value in `status`. This will cause the pod client to
|
||||||
throw an `ex-info` with the associated values.
|
throw an `ex-info` with the associated values.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
@ -245,7 +247,7 @@ time in the future. Async functions must be declared as such as part of the
|
||||||
"vars" [{"name" "watch" "async" "true"}]}]}
|
"vars" [{"name" "watch" "async" "true"}]}]}
|
||||||
```
|
```
|
||||||
|
|
||||||
When calling this function from babashka, the return value is a `core.async`
|
When calling this function from the pod client, the return value is a `core.async`
|
||||||
channel on which the values will be received:
|
channel on which the values will be received:
|
||||||
|
|
||||||
``` clojure
|
``` clojure
|
||||||
|
|
@ -259,8 +261,35 @@ channel on which the values will be received:
|
||||||
|
|
||||||
#### Environment
|
#### Environment
|
||||||
|
|
||||||
Babashka will set the `BABASHKA_POD` environment variable to `true` when
|
The pod client will set the `BABASHKA_POD` environment variable to `true` when
|
||||||
invoking the pod. This can be used by the invoked program to determine whether
|
invoking the pod. This can be used by the invoked program to determine whether
|
||||||
it should behave as a pod or not.
|
it should behave as a pod or not.
|
||||||
|
|
||||||
Added in v0.0.94.
|
Added in v0.0.94.
|
||||||
|
|
||||||
|
#### Client side code
|
||||||
|
|
||||||
|
Pods may implement functions and macros by sending arbitrary code to the pod
|
||||||
|
client in a `"code"` field as part of a `"var"` section. The code is evaluated
|
||||||
|
by the pod client inside the declared namespace.
|
||||||
|
|
||||||
|
For example, a pod can define a macro called `do-twice`:
|
||||||
|
|
||||||
|
``` clojure
|
||||||
|
{"format" "json"
|
||||||
|
"namespaces"
|
||||||
|
[{"name" "pod.babashka.demo"
|
||||||
|
"vars" [{"name" "do-twice" "code" "(defmacro do-twice [x] `(do ~x ~x))"}]}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the pod client:
|
||||||
|
|
||||||
|
``` clojure
|
||||||
|
(pods/load-pod "pod-babashka-demo")
|
||||||
|
(require '[pod.babashka.demo :as demo])
|
||||||
|
(demo/do-twice (prn :foo))
|
||||||
|
;;=>
|
||||||
|
:foo
|
||||||
|
:foo
|
||||||
|
nil
|
||||||
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue