kroki
kroki copied to clipboard
Service discovery
The goal is to allow the gateway server to register additional diagram libraries (that are not built-in). One of the requirement will be to adhere to the Kroki companion container API specification (not yet available).
Proposal
Discovery
When the gateway server starts, it will probe the seed addresses by connecting to each address and attempting to identify the service. If successful, it will register a new service.
discovery.seed_resolver.timeout: 5s
discovery.seed_resolver.max_retry: 5
discovery.seed_hosts:
- 192.168.1.10:1234
- 192.168.1.11
- seeds.mydomain.com
This solution implies that the service must provide information (at least a unique name, a version, and a list of supported formats).
Static registration
Alternatively, we could explicitly register services:
services:
- name: sankey
version: '1.2.3'
endpoint: https://my.domain.org/sankey
formats:
- png
- svg
In this case, the service does not have to expose an API that provides information.
Dynamic registration
We could also support dynamic registration. In this case, the companion service will be responsible for registering itself by sending a request to the gateway server.
POST https://my.kroki/services
{
"name": "mscgen",
"version": "1.2.3",
"formats": ["png", "svg"]
}
-
201 created
: service registration is successful -
422 unprocessable entity
: non-unique name (service is probably already registered) -
400 bad request
: request payload is invalid -
500
: unexpected error
Since Kroki is stateless, registry is held in memory. As a result, the companion service is responsible for registering again in case the gateway server is restarted.
For this reasons, services should send a heartbeat:
PUT https://my.kroki/services/mscgen/heartbeat
-
200 ok
: service found -
404 not found
: service is not registered (use_links
to indicate how to register) -
500
: unexpected error
A service that receives a 404 during a heartbeat could then register again.
The gateway service will provide information about a registred service:
GET https://my.kroki/services/mscgen
{
"name": "mscgen",
"version": "1.2.3",
"formats": ["png", "svg"],
"created_at": "2023-01-01T15:50:05.815479Z",
"updated_at": "2023-01-01T15:50:05.815479Z",
"last_activity_at": "2023-01-01T18:55:04.187568Z"
}
-
200 ok
: service found -
404 not found
: service is not registered -
500
: unexpected error
Note: Last activity date is the last time a service sent a heartbeat or respond to a request from the gateway server.
I will also provide a list of all services currently registered:
GET https://my.kroki/services
[
{
"name": "mscgen",
"version": "1.2.3",
"_links": [
{
"rel": "self",
"href": "/services/mscgen",
"method": "GET"
}
]
}
]
Unregister
A service can unregister (for instance when the service is shutting down) using:
DELETE https://my.kroki/services/mscgen
-
200 ok
: service removed -
404 not found
: service is not registered -
500
: unexpected error
I would add the possibility for an example key (may optional) .
GET https://my.kroki/services/blockdiag
{
"name": "BlockDiag",
"version": "1.2.3",
"formats": ["png", "svg"],
"example": "blockdiag {\n Kroki -> generates -> \"Block diagrams\";\n Kroki -> is -> \"very easy!\";\n\n Kroki [color = \"greenyellow\"];\n \"Block diagrams\" [color = \"pink\"];\n \"very easy!\" [color = \"orange\"];\n}",
"created_at": "2023-01-01T15:50:05.815479Z",
"updated_at": "2023-01-01T15:50:05.815479Z",
"last_activity_at": "2023-01-01T18:55:04.187568Z"
}
It's interesting to note that Vert.x has a service discovery library: https://vertx.io/docs/vertx-service-discovery/java/ One downside is that it would require companion service/container to use an EventBus client to register: https://github.com/vert-x3/vertx-eventbus-bridge-clients
Having said that, we could offer a REST API as a bridge and still leverage Vert.x service discovery library.
I would add the possibility for an example key (may optional) .
What would be the purpose?
to provide an example for a client application e.g. https://kroki.io. When you build something like that you may don't want to change your code for every new service provided via the api.