Skip to content

Commit 21c312b

Browse files
committed
Flow work included
1 parent 6061112 commit 21c312b

File tree

17 files changed

+722
-174
lines changed

17 files changed

+722
-174
lines changed

book/_coverpage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# <img src="https://raw.githubusercontent.com/vertexclique/callysto/master/art/callysto_logo.png">
2-
RUST STREAM PROCESSING FRAMEWORK <small>1.0</small>
2+
RUST STREAM PROCESSING & SERVICE FRAMEWORK <small>1.0</small>
33

44
[![](assets/img/github.svg) GitHub](https://github.com/vertexclique/callysto)
55
[![](assets/img/sitemap-solid.svg) What is Callysto?](https://vertexclique.github.io/callysto/)

book/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
window.$docsify = {
4040
// GENERAL
4141
// -----------------------------------------------------------------
42-
name : 'Callysto - Rust Stream Processing Framework',
42+
name : 'Callysto - Rust Stream Processing & Service Framework',
4343
repo: 'vertexclique/callysto',
4444
coverpage : 'coverpage.md',
4545
homepage : 'introduction.md',

book/qguide.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

book/quickstart.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Quickstart Guide
2+
3+
To include callysto to your project, add this to your `Cargo.toml`.
4+
5+
```toml
6+
callysto = "0.1"
7+
```
8+
9+
## First steps
10+
11+
We initialize the app like below in Callysto:
12+
13+
```rust
14+
use callysto::prelude::*;
15+
16+
fn main() {
17+
let mut app = Callysto::new();
18+
app.with_name("first-steps");
19+
app.run();
20+
}
21+
```
22+
23+
In Callysto, everything is a `Service`, apart from one-off tasks, they belong to `Task` class.
24+
`Service` trait needs to be implemented to implement code that work as a service definition.
25+
Every runnable in Callysto has it's own lifetime. Lifetime of these runnables (tasks, services, agents, etc.)
26+
embedded to their implementation. So you manage stop, start, restart, crash procedures by yourself.
27+
Callysto is not opinionated on how to write your lifecycle procedures. It rather leaves it to user.
28+
29+
30+
## Customizing Configuration
31+
32+
Configuration can be passed differently, even we use some sane defaults you can still change the configuration as in:
33+
```rust
34+
fn main() {
35+
let mut config = Config::default();
36+
config.kafka_config.auto_offset_reset = OffsetReset::Earliest;
37+
38+
let mut app = Callysto::with_state(SharedState::new());
39+
40+
app.with_config(config);
41+
app.with_name("always-read-the-earliest-message");
42+
43+
app.run();
44+
}
45+
46+
```
47+
48+
49+
## Defining a Service
50+
51+
Services and agents are twofold in Callysto: Stateful and Stateless.
52+
Stateful services are the ones that uses global state whereas stateless ones doesn't care and won't use the global application state.
53+
54+
### Stateful Services
55+
Here we are going to show you how to define stateful services.
56+
57+
Here is a boilerplate for a simple service definition which says hi every 5 seconds and also counts how many times it says "hi":
58+
```rust
59+
use std::sync::Arc;
60+
use std::sync::atomic::{AtomicU32, Ordering};
61+
use callysto::prelude::*;
62+
use futures_timer::Delay;
63+
64+
#[derive(Clone)]
65+
struct SharedState {
66+
pub value: Arc<AtomicU32>,
67+
}
68+
69+
impl SharedState {
70+
fn new() -> Self {
71+
Self {
72+
value: Arc::new(AtomicU32::default()),
73+
}
74+
}
75+
}
76+
77+
async fn say_hi_every5_seconds(ctx: Context<SharedState>) -> Result<SharedState> {
78+
let state = ctx.state().to_owned();
79+
println!("{} - Hi from Callysto!", state.value.fetch_add(1, Ordering::SeqCst));
80+
Delay::new(std::time::Duration::from_secs(5)).await;
81+
Ok(state)
82+
}
83+
84+
fn main() {
85+
let mut app = Callysto::with_state(SharedState::new());
86+
app.with_name("sayhi");
87+
app.stateful_service("SayHiEvery5Seconds", say_hi_every5_seconds, vec![]);
88+
89+
app.run();
90+
}
91+
```
92+
93+
### Stateless/Custom Services
94+
95+
Here we will give an example of stateless services.
96+
Stateless services doesn't share a state at application level, or they don't care about the global application state, rather they communicate with each other via messages.
97+
Same example above with no state baked in:
98+
99+
```rust
100+
use callysto::prelude::*;
101+
use futures_timer::Delay;
102+
103+
async fn service_core(ctx: Context<()>) -> Result<()> {
104+
println!("Hi from Callysto!");
105+
Delay::new(std::time::Duration::from_secs(5)).await;
106+
Ok(())
107+
}
108+
109+
fn main() {
110+
let mut app = Callysto::new();
111+
112+
app.with_name("sayhi");
113+
114+
let service = CService::new(
115+
"SayHiEvery5Seconds", // Service name
116+
service_core, // Service function
117+
(), // State, as of now, no state.
118+
vec![] // Dependency services which should start before this service starts.
119+
);
120+
app.service(service);
121+
122+
app.run();
123+
}
124+
```
125+
126+
## Running

book/sidebar.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!-- markdownlint-disable-next-line first-line-heading -->
22
- [Introduction](introduction)
3-
- [Quickstart Guide](qguide)
3+
- [Quickstart Guide](quickstart)
44
- **Sources**
55
- [Sources](sources)
66
- **Flows**

callysto/src/app.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use crate::types::task::Task;
3939
use crate::prelude::*;
4040
use futures::Stream;
4141
use rdkafka::producer::FutureProducer;
42+
use crate::types::flows::{CFlow, Flow};
4243

4344
// TODO: not sure static dispatch is better here. Check on using State: 'static.
4445

@@ -64,6 +65,7 @@ where
6465
services: LOTable<usize, Arc<dyn Service<State>>>,
6566
agents: LOTable<usize, Arc<dyn Agent<State>>>,
6667
tables: LOTable<String, Arc<CTable<State>>>,
68+
flows: LOTable<usize, Arc<dyn Service<State>>>,
6769
table_agents: LOTable<usize, Arc<dyn TableAgent<State>>>,
6870
routes: LOTable<String, Arc<dyn Router<State>>>,
6971
}
@@ -133,6 +135,7 @@ where
133135
services: LOTable::default(),
134136
agents: LOTable::default(),
135137
tables: LOTable::default(),
138+
flows: LOTable::default(),
136139
table_agents: LOTable::default(),
137140
routes: LOTable::default(),
138141
}
@@ -187,6 +190,12 @@ where
187190
self
188191
}
189192

193+
///
194+
/// Get state on demand for global wide access.
195+
pub fn get_state(&mut self) -> State {
196+
self.state.clone()
197+
}
198+
190199
///
191200
/// By default `callysto-app` is used internally as application name.
192201
/// If you want to change this you can use this method.
@@ -314,12 +323,53 @@ where
314323
self
315324
}
316325

326+
/// Helper to define custom service that skips or uses global shared state.
317327
pub fn service(&self, s: impl Service<State>) -> &Self {
318328
let stub = self.stubs.fetch_add(1, Ordering::AcqRel);
319329
self.services.insert(stub, Arc::new(s));
320330
self
321331
}
322332

333+
/// Helper to define flow that skips or uses global shared state.
334+
pub fn flow<T: AsRef<str>, F, S, R, Fut>(&self, name: T, stream: S, clo: F) -> &Self
335+
where
336+
R: 'static + Send,
337+
S: Stream + Send + Sync + 'static,
338+
State: Clone + Send + Sync + 'static,
339+
F: Send + Sync + 'static + Fn(&S, Context<State>) -> Fut,
340+
Fut: Future<Output = CResult<R>> + Send + 'static,
341+
{
342+
let stub = self.stubs.fetch_add(1, Ordering::AcqRel);
343+
let flow = CFlow::new(
344+
stream,
345+
clo,
346+
self.app_name.clone(),
347+
name.as_ref().to_string(),
348+
self.state.clone(),
349+
Vec::default(),
350+
);
351+
self.flows.insert(stub, Arc::new(flow));
352+
self
353+
}
354+
355+
/// Helper to define stateful service that uses global application level state.
356+
pub fn stateful_service<T, F, Fut>(&self, name: T, clo: F, dependencies: Vec<Arc<dyn Service<State>>>) -> &Self
357+
where
358+
T: AsRef<str>,
359+
F: Send + Sync + 'static + Fn(Context<State>) -> Fut,
360+
Fut: Future<Output = CResult<State>> + Send + 'static,
361+
{
362+
let stub = self.stubs.fetch_add(1, Ordering::AcqRel);
363+
let service = CService::new(
364+
name,
365+
clo,
366+
self.state.clone(),
367+
Vec::default(),
368+
);
369+
self.services.insert(stub, Arc::new(service));
370+
self
371+
}
372+
323373
pub fn crontab<C: AsRef<str>>(&self, cron_expr: C, t: impl Task<State>) -> &Self {
324374
let stub = self.stubs.fetch_add(1, Ordering::AcqRel);
325375
let cron_job = Arc::new(CronJob::new(cron_expr, t));

callysto/src/types/agent.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use std::future::Future;
1616
use std::io::Read;
1717
use std::marker::PhantomData as marker;
1818
use std::sync::Arc;
19+
use std::time::Duration;
20+
use futures_timer::Delay;
1921
use tracing::{error, info};
2022

2123
///////////////////////////////////////////////////
@@ -145,7 +147,9 @@ where
145147
}
146148

147149
async fn wait_until_stopped(&self) {
148-
todo!()
150+
while !self.stopped().await {
151+
Delay::new(Duration::from_millis(10)).await;
152+
}
149153
}
150154

151155
async fn state(&self) -> String {

0 commit comments

Comments
 (0)