Skip to content

Commit cf67a00

Browse files
authored
feat: chaos engineered errors in ws (#18)
add `chaos` feature that enables injecting error conditions on websocket connections
2 parents 5a95349 + 0fd0954 commit cf67a00

File tree

8 files changed

+974
-672
lines changed

8 files changed

+974
-672
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export LC_ALL=C
77
export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
88
export TZ=UTC
99

10+
FEATURES=${FEATURES:-default}
1011
TARGET=${TARGET:-$( rustc --print host-tuple )}
1112

1213
export RUSTFLAGS="\
@@ -26,6 +27,7 @@ export CARGO_TARGET_$( echo "${TARGET}" | tr '[:lower:]' '[:upper:]' | tr '-' '_
2627
"
2728

2829
cargo build --package rproxy \
30+
--features ${FEATURES} \
2931
--locked \
3032
--release \
3133
--target ${TARGET}

crates/rproxy/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ path = "src/bin/main.rs"
1111
[lints]
1212
workspace = true
1313

14+
[features]
15+
default = []
16+
17+
chaos = ["rand"]
18+
1419
[dependencies]
1520
actix = "0.13.5"
1621
actix-http = { version = "3.11.1", features = ["ws"] }
@@ -41,6 +46,7 @@ parking_lot = "0.12.4"
4146
pin-project = "1.1.10"
4247
pnet = "0.35.0"
4348
prometheus-client = { git = "https://github.com/0x416e746f6e/client_rust.git", branch = "nested-labels"}
49+
rand = { version = "0.9.2", optional = true }
4450
rustc-hash = "2.1.1"
4551
rustls = "0.23.32"
4652
rustls-pemfile = "2.2.0"

crates/rproxy/src/server/proxy/config/flashblocks.rs

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,48 @@ pub(crate) struct ConfigFlashblocks {
7878
help_heading = "flashblocks",
7979
env = "RPROXY_FLASHBLOCKS_LOG_SANITISE",
8080
long("flashblocks-log-sanitise"),
81-
name("flashblocks-log_sanitise")
81+
name("flashblocks_log_sanitise")
8282
)]
8383
pub(crate) log_sanitise: bool,
84+
85+
/// the chance (between 0.0 and 1.0) that pings received from
86+
/// flashblocks backend would be ignored (no pong sent)
87+
#[arg(
88+
default_value = "0.0",
89+
help_heading = "chaos",
90+
env = "RPROXY_CHAOS_PROBABILITY_FLASHBLOCKS_BACKEND_PING_IGNORED",
91+
long("chaos-probability-flashblocks-backend-ping-ignored"),
92+
name("chaos_probability_flashblocks_backend_ping_ignored"),
93+
value_name = "probability"
94+
)]
95+
#[cfg(feature = "chaos")]
96+
pub(crate) chaos_probability_backend_ping_ignored: f64,
97+
98+
/// the chance (between 0.0 and 1.0) that pings received from
99+
/// flashblocks client would be ignored (no pong sent)
100+
#[arg(
101+
default_value = "0.0",
102+
help_heading = "chaos",
103+
env = "RPROXY_CHAOS_PROBABILITY_FLASHBLOCKS_CLIENT_PING_IGNORED",
104+
long("chaos-probability-flashblocks-client-ping-ignored"),
105+
name("chaos_probability_flashblocks_client_ping_ignored"),
106+
value_name = "probability"
107+
)]
108+
#[cfg(feature = "chaos")]
109+
pub(crate) chaos_probability_client_ping_ignored: f64,
110+
111+
/// the chance (between 0.0 and 1.0) that client's flashblocks stream
112+
/// would block (no more messages sent)
113+
#[arg(
114+
default_value = "0.0",
115+
help_heading = "chaos",
116+
env = "RPROXY_CHAOS_PROBABILITY_FLASHBLOCKS_STREAM_BLOCKED",
117+
long("chaos-probability-flashblocks-stream-blocked"),
118+
name("chaos_probability_flashblocks_stream_blocked"),
119+
value_name = "probability"
120+
)]
121+
#[cfg(feature = "chaos")]
122+
pub(crate) chaos_probability_stream_blocked: f64,
84123
}
85124

86125
impl ConfigFlashblocks {
@@ -119,6 +158,42 @@ impl ConfigFlashblocks {
119158
})
120159
});
121160

161+
#[cfg(feature = "chaos")]
162+
{
163+
// chaos_probability_flashblocks_backend_ping_ignored
164+
if self.chaos_probability_backend_ping_ignored < 0.0 ||
165+
self.chaos_probability_backend_ping_ignored > 1.0
166+
{
167+
errs.push(
168+
ConfigFlashblocksError::ChaosProbabilityFlashblocksBackendPingIgnoredInvalid {
169+
probability: self.chaos_probability_backend_ping_ignored,
170+
},
171+
);
172+
}
173+
174+
// chaos_probability_flashblocks_client_ping_ignored
175+
if self.chaos_probability_client_ping_ignored < 0.0 ||
176+
self.chaos_probability_client_ping_ignored > 1.0
177+
{
178+
errs.push(
179+
ConfigFlashblocksError::ChaosProbabilityFlashblocksClientPingIgnoredInvalid {
180+
probability: self.chaos_probability_client_ping_ignored,
181+
},
182+
);
183+
}
184+
185+
// chaos_probability_flashblocks_stream_blocked
186+
if self.chaos_probability_stream_blocked < 0.0 ||
187+
self.chaos_probability_stream_blocked > 1.0
188+
{
189+
errs.push(
190+
ConfigFlashblocksError::ChaosProbabilityFlashblocksStreamBlockedInvalid {
191+
probability: self.chaos_probability_stream_blocked,
192+
},
193+
);
194+
}
195+
}
196+
122197
match errs.len() {
123198
0 => None,
124199
_ => Some(errs),
@@ -156,6 +231,24 @@ impl ConfigProxyWs for ConfigFlashblocks {
156231
fn log_sanitise(&self) -> bool {
157232
self.log_sanitise
158233
}
234+
235+
#[inline]
236+
#[cfg(feature = "chaos")]
237+
fn chaos_probability_backend_ping_ignored(&self) -> f64 {
238+
self.chaos_probability_backend_ping_ignored
239+
}
240+
241+
#[inline]
242+
#[cfg(feature = "chaos")]
243+
fn chaos_probability_client_ping_ignored(&self) -> f64 {
244+
self.chaos_probability_client_ping_ignored
245+
}
246+
247+
#[inline]
248+
#[cfg(feature = "chaos")]
249+
fn chaos_probability_stream_blocked(&self) -> f64 {
250+
self.chaos_probability_stream_blocked
251+
}
159252
}
160253

161254
// ConfigFlashblocksError ----------------------------------------------
@@ -170,4 +263,22 @@ pub(crate) enum ConfigFlashblocksError {
170263

171264
#[error("invalid flashblocks proxy listen address '{addr}': {err}")]
172265
ListenAddressInvalid { addr: String, err: std::net::AddrParseError },
266+
267+
#[error(
268+
"invalid flashblocks backend ping ignore probability (must be within [0.0 .. 1.0]: {probability}"
269+
)]
270+
#[cfg(feature = "chaos")]
271+
ChaosProbabilityFlashblocksBackendPingIgnoredInvalid { probability: f64 },
272+
273+
#[error(
274+
"invalid flashblocks client ping ignore probability (must be within [0.0 .. 1.0]: {probability}"
275+
)]
276+
#[cfg(feature = "chaos")]
277+
ChaosProbabilityFlashblocksClientPingIgnoredInvalid { probability: f64 },
278+
279+
#[error(
280+
"invalid flashblocks stream block probability (must be within [0.0 .. 1.0]: {probability}"
281+
)]
282+
#[cfg(feature = "chaos")]
283+
ChaosProbabilityFlashblocksStreamBlockedInvalid { probability: f64 },
173284
}

crates/rproxy/src/server/proxy/connection_guard.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ impl Drop for ConnectionGuard {
127127
self.metrics.client_connections_active_count.get_or_create(&metric_labels).set(val);
128128
self.metrics.client_connections_closed_count.get_or_create(&metric_labels).inc();
129129

130-
#[cfg(debug_assertions)]
131130
debug!(
132131
proxy = self.proxy,
133132
connection_id = %self.id,

crates/rproxy/src/server/proxy/ws/config.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,13 @@ pub(crate) trait ConfigProxyWs: Clone + Send + Unpin + 'static {
77
fn log_backend_messages(&self) -> bool;
88
fn log_client_messages(&self) -> bool;
99
fn log_sanitise(&self) -> bool;
10+
11+
#[cfg(feature = "chaos")]
12+
fn chaos_probability_backend_ping_ignored(&self) -> f64;
13+
14+
#[cfg(feature = "chaos")]
15+
fn chaos_probability_client_ping_ignored(&self) -> f64;
16+
17+
#[cfg(feature = "chaos")]
18+
fn chaos_probability_stream_blocked(&self) -> f64;
1019
}

0 commit comments

Comments
 (0)