Crate teravolt[−][src]
Teravolt is an executor for handling streaming data from multiple sources and enabling seamless communication between them.
Getting started
There are three main components to getting Teravolt up and running:
Creating a Connection
To create a new connection, we need to create a blank struct, like so:
#[derive(Clone)] struct SendMessage;
It is very important that our struct is cloneable. Next we need to implement
the actual Connection
. When implementing a connection we need to create
a global error type that will be used across all connections running in the
executor. This can reasonably be anything but for now, ()
will be adequate
for demonstration. An implementation for a Connection
will look like
this:
#[teravolt::async_trait] impl Connection<Error> for SendMessage { fn config(&self) -> ConnectionConfig { // ... } fn policy(&self, _: TaskResult<Error>) -> RestartPolicy { // ... } async fn task(&self, sender: &Sender, _: &mut Receiver) -> TaskResult<Error> { // ... } }
Config
This is how we determine the behaviour of the connection. For instance, a config will look this:
fn config(&self) -> ConnectionConfig { ConnectionConfig { name: "SendMessage", behaviour: ConnectionBehaviour::Producer, } }
Here we define the name of the connection and it’s behaviour. The name of
the connection must be unique inside the executor. The behaviour determines
how the connection will deal with receiving and sending messages. There is a
Producer, Consumer, and Transformer behaviour type. To learn more about what
these do, read the ConnectionBehaviour
documentation.
Restart Policy
The restart policy will determine what happens when the task either completes or fails. It takes the result produced by the task and it is up to you to determine what circumstances will cause a Restart or a Shutdown. A restart policy will sometimes look like this:
fn policy(&self, result: TaskResult<Error>) -> RestartPolicy { if let Err(error) = result { RestartPolicy::Restart } else { RestartPolicy::Shutdown } }
Task
Each connection has an asynchronous task that is responsible for reading in messages and sending them to other connections. A task will sometimes look like this:
async fn task(&self, sender: &Sender, _: &mut Receiver) -> TaskResult<()> { let mut interval = time::interval(Duration::from_millis(1000)); loop { interval.tick().await; if let Err(_) = sender.send(Type.as_message()) { break; } } Ok(()) }
A task has the ability to read messages sent from other connections and send
messages from other connections. The ability to read and write is determined
by the connection’s ConnectionBehaviour
.
Messages
In Teravolt, a Message
is a universal type for sending data between
connections. To allow your types to be sent as a message, do the following:
#[derive(Clone, TeravoltMessage)] struct MyType;
Make sure that your type implements Clone
, otherwise you will get an
error.
Executor
The executor is the main manager for all of the connections you’ll be running. Setting up the executor is quite simple, first you need to create a tokio runtime with the right features enabled for your use-case:
let runtime = Builder::new_multi_thread() .thread_name("teravolt-worker") .thread_stack_size(3 * 1024 * 1024) .enable_time() .build() .unwrap();
Then once you’ve made the runtime you can create an instance of the executor, add your connections, and then start it!
let mut teravolt = Executor::new(&runtime).unwrap(); teravolt.add_connection(MyConnection); teravolt.start().await;
Re-exports
pub use crate::executor::Connection; |
pub use crate::executor::Executor; |
pub use crate::message::Message; |
Modules
config | |
error | |
executor | |
message | |
prelude | |
types |
Type Definitions
Result | A |
Attribute Macros
async_trait | A re-export of [ |