Skip to content

Commit c6016a9

Browse files
authored
named Distributor (#319)
* wip * wip, a lot left! * a bit of debug statements and more funsies * tell and tell_everyone are working. * ok we're almost there, lets see if i can handle a vec<replies> and if i can register ppl to a new Distributor * yay it works! * lints * 19 lints remaining * 9 warnings to go * docs + tests * i think we re good to go * example fix * san * move miri to a .sh file * bump nightlies and anyhow * clippy pass + prepare to merge
1 parent e923d55 commit c6016a9

21 files changed

+1282
-63
lines changed

.github/workflows/miri.yml

+2-11
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Install
1515
uses: actions-rs/toolchain@v1
1616
with:
17-
toolchain: nightly-2021-01-01
17+
toolchain: nightly-2021-03-20
1818
override: true
1919
- uses: davidB/rust-cargo-make@v1
2020
with:
@@ -24,13 +24,4 @@ jobs:
2424
RUST_BACKTRACE: full
2525
RUST_LOG: 'trace'
2626
run: |
27-
rustup component add miri
28-
cargo miri setup
29-
cargo clean
30-
# Do some Bastion shake
31-
cd src/bastion && \
32-
MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" cargo miri test --features lever/nightly dispatcher && \
33-
MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" cargo miri test --features lever/nightly path && \
34-
MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" cargo miri test --features lever/nightly broadcast && \
35-
MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" cargo miri test --features lever/nightly children_ref && \
36-
cd -
27+
tools/miri.sh

.github/workflows/sanitizers.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
- name: Install
1616
uses: actions-rs/toolchain@v1
1717
with:
18-
toolchain: nightly-2021-01-01
18+
toolchain: nightly-2021-03-20
1919
override: true
2020
- uses: davidB/rust-cargo-make@v1
2121
with:

src/bastion-executor/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ tokio-runtime = ["tokio"]
3030

3131
[dependencies]
3232
bastion-utils = "0.3.2"
33-
lightproc = "0.3"
33+
# lightproc = "0.3"
34+
lightproc = { path = "../lightproc" }
3435
# bastion-utils = { path = "../bastion-utils" }
3536

3637
crossbeam-utils = "0.8"

src/bastion-executor/src/placement.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn get_num_cores() -> Option<usize> {
1818
///
1919
/// Sets the current threads affinity
2020
pub fn set_for_current(core_id: CoreId) {
21-
tracing::info!("Executor: placement: set affinity on core {}", core_id.id);
21+
tracing::trace!("Executor: placement: set affinity on core {}", core_id.id);
2222
set_for_current_helper(core_id);
2323
}
2424

src/bastion/Cargo.toml

+7-3
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ rustdoc-args = ["--cfg", "feature=\"docs\""]
5252
[dependencies]
5353
bastion-executor = { git = "https://github.com/bastion-rs/bastion.git" }
5454
lightproc = "0.3"
55-
# bastion-executor = { version = "= 0.3.7-alpha.0", path = "../bastion-executor" }
56-
# lightproc = { version = "= 0.3", path = "../lightproc" }
55+
# bastion-executor = { path = "../bastion-executor" }
56+
# lightproc = { path = "../lightproc" }
5757

5858
lever = "0.1"
5959
futures = "0.3.5"
@@ -73,9 +73,12 @@ artillery-core = { version = "0.1.2-alpha.3", optional = true }
7373
# Log crates
7474
tracing-subscriber = "0.2.6"
7575
tracing = "0.1.15"
76-
anyhow = "1.0.31"
76+
anyhow = "1.0"
7777
crossbeam-queue = "0.3.0"
7878
log = "0.4.14"
79+
lasso = {version = "0.5", features = ["multi-threaded"] }
80+
once_cell = "1.7.2"
81+
thiserror = "1.0.24"
7982

8083
[target.'cfg(not(windows))'.dependencies]
8184
nuclei = "0.1"
@@ -91,6 +94,7 @@ rayon = "1.3.1"
9194
num_cpus = "1.13.0"
9295
# hello_tokio example
9396
tokio = { version="1.1", features = ["time", "macros"] }
97+
# bastion-executor = { path = "../bastion-executor" }
9498
bastion-executor = { git = "https://github.com/bastion-rs/bastion.git" }
9599
once_cell = "1.5.2"
96100
tokio-test = "0.4.0"

src/bastion/examples/distributor.rs

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
///! Create a conference.
2+
///!
3+
///! 1st Group
4+
///! Staff (5) - Going to organize the event // OK
5+
///!
6+
///! 2nd Group
7+
///! Enthusiasts (50) - interested in participating to the conference (haven't registered yet) // OK
8+
///!
9+
///! 3rd Group
10+
///! Attendees (empty for now) - Participate
11+
///!
12+
///! Enthusiast -> Ask one of the staff members "when is the conference going to happen ?" // OK
13+
///! Broadcast / Question => Answer 0 or 1 Staff members are going to reply eventually? // OK
14+
///!
15+
///! Staff -> Send a Leaflet to all of the enthusiasts, letting them know that they can register. // OK
16+
///!
17+
///! "hey conference <awesomeconference> is going to happen. will you be there?"
18+
///! Broadcast / Question -> if people reply with YES => fill the 3rd group
19+
///! some enthusiasts are now attendees
20+
///!
21+
///! Staff -> send the actual schedule and misc infos to Attendees
22+
///! Broadcast / Statement (Attendees)
23+
///!
24+
///! An attendee sends a thank you note to one staff member (and not bother everyone)
25+
///! One message / Statement (Staff) // OK
26+
///!
27+
///! ```rust
28+
///! let staff = Distributor::named("staff");
29+
///! let enthusiasts = Distributor::named("enthusiasts");
30+
///! let attendees = Disitributor::named("attendees");
31+
///! // Enthusiast -> Ask the whole staff "when is the conference going to happen ?"
32+
///! ask_one(Message + Clone) -> Result<impl Future<Output = Reply>, CouldNotSendError>
33+
///! // await_one // await_all
34+
///! // first ? means "have we been able to send the question?"
35+
///! // it s in a month
36+
///! let replies = staff.ask_one("when is the conference going to happen ?")?.await?;
37+
///! ask_everyone(Message + Clone) -> Result<impl Stream<Item = Reply>, CouldNotSendError>
38+
///! let participants = enthusiasts.ask_everyone("here's our super nice conference, it s happening people!").await?;
39+
///! for participant in participants {
40+
///! // grab the sender and add it to the attendee recipient group
41+
///! }
42+
///! // send the schedule
43+
///! tell_everyone(Message + Clone) -> Result<(), CouldNotSendError>
44+
///! attendees.tell_everyone("hey there, conf is in a week, here s where and how it s going to happen")?;
45+
///! // send a thank you note
46+
///! tell(Message) -> Result<(), CouldNotSendError>
47+
///! staff.tell_one("thank's it was amazing")?;
48+
///! children
49+
///! .with_redundancy(10)
50+
///! .with_distributor(Distributor::named("staff"))
51+
///! // We create the function to exec when each children is called
52+
///! .with_exec(move |ctx: BastionContext| async move { /* ... */ })
53+
///! children
54+
///! .with_redundancy(100)
55+
///! .with_distributor(Distributor::named("enthusiasts"))
56+
///! // We create the function to exec when each children is called
57+
///! .with_exec(move |ctx: BastionContext| async move { /* ... */ })
58+
///! children
59+
///! .with_redundancy(0)
60+
///! .with_distributor(Distributor::named("attendees"))
61+
///! // We create the function to exec when each children is called
62+
///! .with_exec(move |ctx: BastionContext| async move { /* ... */ })
63+
///! ```
64+
use anyhow::{anyhow, Context, Result as AnyResult};
65+
use bastion::distributor::*;
66+
use bastion::prelude::*;
67+
use tracing::Level;
68+
69+
// true if the person attends the conference
70+
#[derive(Debug)]
71+
struct RSVP {
72+
attends: bool,
73+
child_ref: ChildRef,
74+
}
75+
76+
#[derive(Debug, Clone)]
77+
struct ConferenceSchedule {
78+
start: std::time::Duration,
79+
end: std::time::Duration,
80+
misc: String,
81+
}
82+
83+
/// cargo r --features=tokio-runtime distributor
84+
#[tokio::main]
85+
async fn main() -> AnyResult<()> {
86+
let subscriber = tracing_subscriber::fmt()
87+
.with_max_level(Level::INFO)
88+
.finish();
89+
tracing::subscriber::set_global_default(subscriber).unwrap();
90+
91+
// Initialize bastion
92+
Bastion::init();
93+
94+
// 1st Group
95+
Bastion::supervisor(|supervisor| {
96+
supervisor.children(|children| {
97+
// Iniit staff
98+
// Staff (5 members) - Going to organize the event
99+
children
100+
.with_redundancy(5)
101+
.with_distributor(Distributor::named("staff"))
102+
.with_exec(organize_the_event)
103+
})
104+
})
105+
// 2nd Group
106+
.and_then(|_| {
107+
Bastion::supervisor(|supervisor| {
108+
supervisor.children(|children| {
109+
// Enthusiasts (50) - interested in participating to the conference (haven't registered yet)
110+
children
111+
.with_redundancy(50)
112+
.with_distributor(Distributor::named("enthusiasts"))
113+
.with_exec(be_interested_in_the_conference)
114+
})
115+
})
116+
})
117+
.map_err(|_| anyhow!("couldn't setup the bastion"))?;
118+
119+
Bastion::start();
120+
121+
// Wait a bit until everyone is ready
122+
// std::thread::sleep(std::time::Duration::from_secs(1));
123+
124+
let staff = Distributor::named("staff");
125+
let enthusiasts = Distributor::named("enthusiasts");
126+
let attendees = Distributor::named("attendees");
127+
128+
// Enthusiast -> Ask one of the staff members "when is the conference going to happen ?"
129+
let answer = staff.ask_one("when is the next conference going to happen?")?;
130+
MessageHandler::new(
131+
answer
132+
.await
133+
.expect("coulnd't find out when the next conference is going to happen :("),
134+
)
135+
.on_tell(|reply: String, _sender_addr| {
136+
tracing::info!("received a reply to my message:\n{}", reply);
137+
});
138+
139+
// "hey conference <awesomeconference> is going to happen. will you be there?"
140+
// Broadcast / Question -> if people reply with YES => fill the 3rd group
141+
let answers = enthusiasts
142+
.ask_everyone("hey, the conference is going to happen, will you be there?")
143+
.expect("couldn't ask everyone");
144+
145+
for answer in answers.into_iter() {
146+
MessageHandler::new(answer.await.expect("couldn't receive reply"))
147+
.on_tell(|rsvp: RSVP, _| {
148+
if rsvp.attends {
149+
tracing::info!("{:?} will be there! :)", rsvp.child_ref.id());
150+
attendees
151+
.subscribe(rsvp.child_ref)
152+
.expect("couldn't subscribe attendee");
153+
} else {
154+
tracing::error!("{:?} won't make it :(", rsvp.child_ref.id());
155+
}
156+
})
157+
.on_fallback(|unknown, _sender_addr| {
158+
tracing::error!(
159+
"distributor_test: uh oh, I received a message I didn't understand\n {:?}",
160+
unknown
161+
);
162+
});
163+
}
164+
165+
// Ok now that attendees have subscribed, let's send information around!
166+
tracing::info!("Let's send invitations!");
167+
// Staff -> send the actual schedule and misc infos to Attendees
168+
let total_sent = attendees
169+
.tell_everyone(ConferenceSchedule {
170+
start: std::time::Duration::from_secs(60),
171+
end: std::time::Duration::from_secs(3600),
172+
misc: "it's going to be amazing!".to_string(),
173+
})
174+
.context("couldn't let everyone know the conference is available!")?;
175+
176+
tracing::error!("total number of attendees: {}", total_sent.len());
177+
178+
tracing::info!("the conference is running!");
179+
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
180+
181+
// An attendee sends a thank you note to one staff member (and not bother everyone)
182+
staff
183+
.tell_one("the conference was amazing thank you so much!")
184+
.context("couldn't thank the staff members :(")?;
185+
186+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
187+
// And we're done!
188+
Bastion::stop();
189+
190+
// BEWARE, this example doesn't return
191+
Bastion::block_until_stopped();
192+
193+
Ok(())
194+
}
195+
196+
async fn organize_the_event(ctx: BastionContext) -> Result<(), ()> {
197+
loop {
198+
MessageHandler::new(ctx.recv().await?)
199+
.on_question(|message: &str, sender| {
200+
tracing::info!("received a question: \n{}", message);
201+
sender
202+
.reply("uh i think it will be next month!".to_string())
203+
.unwrap();
204+
})
205+
.on_tell(|message: &str, _| {
206+
tracing::info!("received a message: \n{}", message);
207+
})
208+
.on_fallback(|unknown, _sender_addr| {
209+
tracing::error!(
210+
"staff: uh oh, I received a message I didn't understand\n {:?}",
211+
unknown
212+
);
213+
});
214+
}
215+
}
216+
217+
async fn be_interested_in_the_conference(ctx: BastionContext) -> Result<(), ()> {
218+
loop {
219+
MessageHandler::new(ctx.recv().await?)
220+
.on_tell(|message: std::sync::Arc<&str>, _| {
221+
tracing::info!(
222+
"child {}, received a broadcast message:\n{}",
223+
ctx.current().id(),
224+
message
225+
);
226+
})
227+
.on_tell(|schedule: ConferenceSchedule, _| {
228+
tracing::info!(
229+
"child {}, received broadcast conference schedule!:\n{:?}",
230+
ctx.current().id(),
231+
schedule
232+
);
233+
})
234+
.on_question(|message: &str, sender| {
235+
tracing::info!("received a question: \n{}", message);
236+
// ILL BE THERE!
237+
sender
238+
.reply(RSVP {
239+
attends: rand::random(),
240+
child_ref: ctx.current().clone(),
241+
})
242+
.unwrap();
243+
});
244+
}
245+
}

src/bastion/examples/hello_tokio.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
#[cfg(feature = "tokio-runtime")]
12
use anyhow::Result as AnyResult;
3+
#[cfg(feature = "tokio-runtime")]
24
use bastion::prelude::*;
35
#[cfg(feature = "tokio-runtime")]
46
use tokio;
7+
#[cfg(feature = "tokio-runtime")]
58
use tracing::{error, warn, Level};
69

710
/// `cargo run --features=tokio-runtime --example hello_tokio`

src/bastion/examples/prime_numbers.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ mod prime_number {
7272
fn number_or_panic(number_to_return: u128) -> u128 {
7373
// Let's roll a dice
7474
if rand::random::<u8>() % 6 == 0 {
75-
panic!(format!(
75+
panic!(
7676
"I was about to return {} but I chose to panic instead!",
7777
number_to_return
78-
))
78+
)
7979
}
8080
number_to_return
8181
}

0 commit comments

Comments
 (0)