crows_utils/services/
mod.rs

1use std::{collections::HashMap, time::Duration};
2
3use crate::{self as utils};
4use crows_service::service;
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7use uuid::Uuid;
8
9#[derive(Error, Debug, Serialize, Deserialize, Clone)]
10pub enum CoordinatorError {
11    #[error("could not upload a module")]
12    UploadModuleError,
13    #[error("couldn't find module {0}")]
14    NoSuchModule(String),
15    #[error("Failed to create runtime: {0}")]
16    FailedToCreateRuntime(String),
17    #[error("Failed to compile module")]
18    FailedToCompileModule,
19    #[error("Couldn't fetch config: {0}")]
20    CouldNotFetchConfig(String),
21}
22
23#[derive(Error, Debug, Serialize, Deserialize, Clone)]
24pub enum WorkerError {
25    #[error("could not upload a module")]
26    UploadModuleError,
27    #[error("could not find a requested scenario")]
28    ScenarioNotFound,
29    #[error("could not create a module from binary")]
30    CouldNotCreateModule,
31    #[error("could not create runtime: {0}")]
32    CouldNotCreateRuntime(String),
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
36pub struct RunId(Uuid);
37
38impl RunId {
39    pub fn new() -> Self {
40        Self(Uuid::new_v4())
41    }
42}
43
44impl Into<Uuid> for RunId {
45    fn into(self) -> Uuid {
46        self.0
47    }
48}
49
50// TODO: I don't like the fact that I need to specify the "other_side"
51// here. It would be better if it was only needed when connecting, then
52// all the trait definitions wouldn't have to be here
53#[service(variant = "server", other_side = Worker)]
54pub trait WorkerToCoordinator {
55    async fn ping(&self) -> String;
56}
57
58#[derive(Serialize, Deserialize, Debug, Clone)]
59pub enum WorkerStatus {
60    Available,
61    Busy,
62}
63
64#[service(variant = "server", other_side = Client)]
65pub trait Coordinator {
66    async fn upload_scenario(name: String, content: Vec<u8>) -> Result<(), CoordinatorError>;
67    async fn start(
68        name: String,
69        workers_number: usize,
70    ) -> Result<(RunId, Vec<String>), CoordinatorError>;
71    async fn list_workers() -> Vec<String>;
72    async fn get_run_status(&self, id: RunId) -> Option<HashMap<String, RunInfo>>;
73}
74
75#[derive(Serialize, Deserialize, Debug, Clone)]
76pub struct WorkerData {
77    pub id: Uuid,
78    pub hostname: String,
79}
80
81#[derive(Clone, Serialize, Deserialize, Debug)]
82pub struct RequestInfo {
83    pub latency: Duration,
84    pub successful: bool,
85}
86
87#[derive(Clone, Serialize, Deserialize, Debug)]
88pub struct IterationInfo {
89    pub latency: Duration,
90}
91
92#[derive(Default, Clone, Serialize, Deserialize, Debug)]
93pub struct RunInfo {
94    pub iteration_stats: Vec<IterationInfo>,
95    pub request_stats: Vec<RequestInfo>,
96    pub stderr: Vec<Vec<u8>>,
97    pub stdout: Vec<Vec<u8>>,
98    pub done: bool,
99    pub elapsed: Option<Duration>,
100    pub left: Option<Duration>,
101    pub active_instances_delta: isize,
102    pub capacity_delta: isize,
103}
104
105#[service(variant = "client", other_side = WorkerToCoordinator)]
106pub trait Worker {
107    async fn upload_scenario(&self, name: String, content: Vec<u8>);
108    async fn ping(&self) -> String;
109    async fn start(
110        &self,
111        name: String,
112        config: crows_shared::Config,
113        run_id: RunId,
114    ) -> Result<(), WorkerError>;
115    async fn get_data(&self) -> WorkerData;
116    async fn get_run_status(&self, id: RunId) -> RunInfo;
117}
118
119#[service(variant = "client", other_side = Coordinator)]
120pub trait Client {}