Add specs.
This commit is contained in:
101
README.md
Normal file
101
README.md
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# `slingshot-microservice`: A Rust framework for standard microservice design
|
||||||
|
|
||||||
|
`slingshot-microservice` is a Rust package that provides a simple, opinionated
|
||||||
|
framework for building microservices. The framework makes the following
|
||||||
|
assumptions about a microservice:
|
||||||
|
|
||||||
|
1. Microservices listens to incoming requests on a RabbitMQ queue.
|
||||||
|
2. Incoming requests are in the form of a 64-bit unsigned integer (enough
|
||||||
|
granularity to work as a resource identifier or ID).
|
||||||
|
2. Microservices process incoming requests via a `process` function, which
|
||||||
|
takes one argument: the incoming request (`u64`).
|
||||||
|
3. The `process` function returns a set of IDs (also `u64`) that are the result
|
||||||
|
of processing the incoming request. Each of these IDs is also associated
|
||||||
|
with a "case variable" that is used for routing the result to the
|
||||||
|
appropriate outbound queues.
|
||||||
|
4. Rather than hard-coding the inbound and outbound RabbitMQ queues, the
|
||||||
|
microservice communicates with a configuration service which provides the
|
||||||
|
inbound queue name, as well as any outbound queues and their corresponding case variables.
|
||||||
|
|
||||||
|
The `slingshot-microservice` framework handles setting up the RabbitMQ
|
||||||
|
connection, listening to the inbound queue and routing results based on case variables.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use slingshot_microservice::Microservice;
|
||||||
|
|
||||||
|
fn process(request: u64) -> Vec<(u64, String)> {
|
||||||
|
// Example processing logic: return the request ID and a case variable
|
||||||
|
vec![(request, "case_a".to_string())]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Create a new microservice instance with the processing function
|
||||||
|
let microservice = Microservice::new(
|
||||||
|
"simple-microservice",
|
||||||
|
"sys-map.example.com",
|
||||||
|
process
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start the microservice (this will block and listen for incoming requests)
|
||||||
|
microservice.start();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## How it works:
|
||||||
|
|
||||||
|
The configuration service responds to requests of the form:s
|
||||||
|
`https://{HOSTNAME}/{MICROSERVICE_NAME}` with a JSON object that contains the
|
||||||
|
inbound queue name and a mapping of case variables to outbound queue names.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"in": "simple-microservice-inbound",
|
||||||
|
"out": [
|
||||||
|
{
|
||||||
|
"case": "case_a",
|
||||||
|
"queues": ["case_a_outbound_1", "case_a_outbound_2"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case": "case_b",
|
||||||
|
"queue": ["case_b_outbound"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The case variables can be any primitive type (e.g. string, integer, boolean).
|
||||||
|
E.g. a binary classification microservice might decide on which outbound queue
|
||||||
|
to send results to based on a case variable that is either `false` or `true`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"in": "binary-classification-inbound",
|
||||||
|
"out": [
|
||||||
|
{
|
||||||
|
"case": false,
|
||||||
|
"queues": ["binary-classification-false-outbound"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case": true,
|
||||||
|
"queue": ["binary-classification-true-outbound"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When the microservice first starts up, it makes a request to the configuration
|
||||||
|
service to get the queue metadata. Then it starts to listen to the inbound
|
||||||
|
queue. Inbound requests are processed by the user-programmed `process`
|
||||||
|
function, which returns a set of tuples of the form `(result_id, case_variable)`.
|
||||||
|
The microservice then routes each `result_id` to the appropriate outbound
|
||||||
|
queue(s) based on the `case_variable`, using a process that looks like this:
|
||||||
|
|
||||||
|
Pseudocode:
|
||||||
|
```
|
||||||
|
for each (result_id, case_variable) in process(request):
|
||||||
|
for each outbound_queue in config.out[case_variable]:
|
||||||
|
send result_id to outbound_queue
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user