Gilmour is a framework for writing micro-services that exchange data over non-http transports. Currently the supported backend is Redis PubSub. Redis pubsub channels are used like "routes". Gilmour started off simply as a non-http alternative to Sinatra, but has grown into a feature rich microservices communication library and framework.
Gilmour enables two patterns of communication:
This is the most common pattern found in microservice architectures. An entity
sends a request
, and a subscriber processes it and sends a reply
. See
examples/fibonacci.rb
as an example. Gilmour also allows horizontal scaling
by using exclusion groups. When there are multiple instances of a subscriber running, only one subscriber from an exclusion group processes that request.
Eg, if you run container.rb
from the examples multiple times simultaneously, running echoclient.rb
or forkechoclient.rb
will produce the same result, irrespective of how many instances of the container are running. (More of containers later).
A less common, but very powerful pattern is event driven service design, or the signal-slot pattern (a term borrowed from the Qt library). One service emits or signals events, which are picked up by one or more subscribers and processed. None of the subscribers send a reply, because a reply really has no meaning in this context. See examples/signal_slot.rb
.
Which pattern to chose, is primarily dependent on the ownership of failure. If the subscribers own the failures they encounter, then you should consider the signal-slot pattern.
It is also possible to have slots as well as reply subscribers for a given message. Gilmour provides a utility broadcast
which internally does a signal and a request.
Microservices increase the granularity of our services oriented architectures. Borrowing from unix philosohy, they should do one thing and do it well. However, for this to be really useful, there should be a facility such as is provided by unix shells. Unix shells allow the composition of small commands using the following methods
- Composition:
cmd1 | cmd2 | cmd2
- AndAnd:
cmd1 && cmd2 && cmd3
- Batch:
cmd1; cmd2; cmd3 > out
or(cmd1; cmd2; cmd3) > out
- Parallel: This runs stages in parallel call the callback when all are done. The data passed to the callback is an array of {:data, :code} hashes in no particular order. The code is the highest error code from the array.
Also, you should be able to use these methods of composition in any combination and also in a nexted manner - (cmd1 | cmd2) && cmd3
. Gilmour enables you to do just that. See examples/composition.rb
.
Gilmour uses it's own simple protocol to send request and response "headers". The structure of the payload is a simple JSON as shown below:
{
data: The actual payload,
sender: The origin of the request (unique for each request),
code: The response code if this is a response. This uses HTTP error codes
}
Gilmour has builtin support for error publishing. The error channel is separate from the response channels and everything that is put on the error channel is prefixed by the per-request unique sender uuid, which makes debugging easier. The error packet protocol is
{
code: response code (non-200)
sender: the "sender" from the request
topic: the topic to which the request was sent
request_data: the request payload
userdata: implementation dependent debug infomation
backtrace: the backtrace of the error
timestamp: the timestamp of the error
}
The sender
field actually represents a unique sender key. Any reponse that
is to be sent to the request is sent on the "reservered" topic
response.<sender>
on the same exchange.
For the request-reply pattern, the topic is prefixed with gilmour.request
.
For the signal-slot pettern, the topic is prefixed with gilmour.slot
.
The topic on which errors are published is gilmour.error
.
Gilmour code can be structured such that the subscribers are auto-loaded from the filesystem. This enables creation of containers which house multiple microservices, with a choice of which ones to enable. See examples/container.rb
.
Gilmour supports health monitoring heartbeats. Every gilmour process, which has health monitoring enabled, listens for hearbeat pings and responds accordingly. External monitors can use this to monitor the health. The health bulletin and the health-tools are examples of such tools.
See the examples
directory
To run the specs, set REDIS_HOST
(default is localhost) and REDIS_PORT
(default is 6379)
to point to your rabbitmq or redis server.
Then, from within the test
directory, run rspec spec/*