Introduction

A nameko like lib in rust

Description

A nameko-rpc like lib in rust. Check the To-Do section to see limitation.

Do not use in production!

Girolle use Nameko architecture to send request and get response.

Stack

Girolle use lapin as an AMQP client/server library.

How to use it

The core concept is to remove the pain of the queue creation and reply by mokcing the Nameko architecture, and to use an abstract type serde_json::Value to manipulate a serializable data.

macro procedural

The lib offer a procedural macro #[girolle] to create a Task like this:

use girolle::prelude::*;

#[girolle]
fn hello(s: String) -> String {
    format!("Hello, {}!", s)
}

The macro do a real complexe job. It transform the function into three functions:

  • The first function is a copy of the original function with a suffix _core.
  • The second one is just a wrapper to deserialize the input and serialize the output with serde_json.
  • The thrid one is the creation of the RpcTask.

It returns a fn()->RpcTask that can be used to register to the RpcService.

The macro is set to replace recursively the function call in the function body to call the _core function. It may result in a issue with the #[girolle] macro. For example:

#[girolle]
fn sleep(n: u64) -> String {
    thread::sleep(time::Duration::from_secs(n));
    format!("Slept for {} seconds", n)
}

The thread::sleep will be replace by the thread::sleep_core function call and the function will not sleep.

hand made deserialization and serialization

if you do not use the macro #[girolle] you need to create a function that extract the data from the a &[Value] like this and return a Result<Value>:

fn fibonacci(n: u64) -> u64 {
    if n <= 1 {
        return n;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

fn fibonacci_wrap(s: &[Value]) -> Result<Value> {
    // extract the data from the Value
    let n: u64 = serde_json::from_value(s[0].clone())?;
    // create the result
    let result: Value = serde_json::to_value(fibonacci(n))?;
    // return the result in a Result
    Ok(result)
}

fn fibonacci_task() -> RpcTask {
    RpcTask::new("fibonacci", vec!["n"], fibonacci)
}

As you can see it is little bit more complexe than the macro. To create the RpcTask we need to set the name of the method, the list of the argument and the function that will be called. With this breabdown workflow you get more control to like the method register in the AMQP server.