Federated relay tier: peer flooding, per-member isolation, registry admission and relay discovery
This commit is contained in:
+52
-13
@@ -478,38 +478,53 @@ async fn stale_envelopes_are_rejected() {
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn backpressure_is_visible_and_recoverable() {
|
||||
async fn lagging_member_is_isolated_and_reported() {
|
||||
let relay_url = spawn_relay_with_capacity(1).await;
|
||||
let http = client();
|
||||
let member = Keypair::generate();
|
||||
let active = Keypair::generate();
|
||||
let slow = Keypair::generate();
|
||||
let publisher = Keypair::generate();
|
||||
register(&http, &relay_url, &member).await;
|
||||
register(&http, &relay_url, &active).await;
|
||||
register(&http, &relay_url, &slow).await;
|
||||
|
||||
let first = query_envelope(&publisher, &publisher.public_hex(), "one", 5);
|
||||
assert_eq!(
|
||||
publish(&http, &relay_url, &first).await.status(),
|
||||
reqwest::StatusCode::ACCEPTED
|
||||
);
|
||||
assert_eq!(
|
||||
poll_messages(&http, &relay_url, &active, 300).await.len(),
|
||||
1
|
||||
);
|
||||
|
||||
let second = query_envelope(&publisher, &publisher.public_hex(), "two", 5);
|
||||
let response = publish(&http, &relay_url, &second).await;
|
||||
assert_eq!(
|
||||
publish(&http, &relay_url, &second).await.status(),
|
||||
reqwest::StatusCode::ACCEPTED,
|
||||
"a lagging subscriber must not stall publishers"
|
||||
);
|
||||
assert_eq!(
|
||||
poll_messages(&http, &relay_url, &active, 300).await.len(),
|
||||
1
|
||||
);
|
||||
|
||||
let response = poll(&http, &relay_url, &slow, 300).await;
|
||||
assert_eq!(response.status(), reqwest::StatusCode::TOO_MANY_REQUESTS);
|
||||
assert_eq!(
|
||||
response
|
||||
.headers()
|
||||
.get("retry-after")
|
||||
.and_then(|v| v.to_str().ok()),
|
||||
.and_then(|value| value.to_str().ok()),
|
||||
Some("1")
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
poll_messages(&http, &relay_url, &member, 300).await.len(),
|
||||
1
|
||||
let payload: Value = response.json().await.unwrap();
|
||||
assert!(
|
||||
payload.get("missed").and_then(Value::as_u64).unwrap_or(0) >= 1,
|
||||
"lagging member must be told how much it missed: {payload}"
|
||||
);
|
||||
assert_eq!(
|
||||
poll_messages(&http, &relay_url, &publisher, 300)
|
||||
.await
|
||||
.len(),
|
||||
1
|
||||
poll(&http, &relay_url, &slow, 50).await.status(),
|
||||
reqwest::StatusCode::NO_CONTENT
|
||||
);
|
||||
|
||||
let third = query_envelope(&publisher, &publisher.public_hex(), "three", 5);
|
||||
@@ -517,6 +532,30 @@ async fn backpressure_is_visible_and_recoverable() {
|
||||
publish(&http, &relay_url, &third).await.status(),
|
||||
reqwest::StatusCode::ACCEPTED
|
||||
);
|
||||
assert_eq!(poll_messages(&http, &relay_url, &slow, 300).await.len(), 1);
|
||||
|
||||
let fourth = query_envelope(&publisher, &publisher.public_hex(), "four", 5);
|
||||
assert_eq!(
|
||||
publish(&http, &relay_url, &fourth).await.status(),
|
||||
reqwest::StatusCode::ACCEPTED
|
||||
);
|
||||
let fifth = query_envelope(&publisher, &publisher.public_hex(), "five", 5);
|
||||
assert_eq!(
|
||||
publish(&http, &relay_url, &fifth).await.status(),
|
||||
reqwest::StatusCode::ACCEPTED
|
||||
);
|
||||
let direct = test_envelope(
|
||||
&publisher,
|
||||
TYPE_RESPONSE,
|
||||
json!({"qid": "q", "results": [], "truncated": false, "more_available": 0, "cursor": null}),
|
||||
);
|
||||
assert_eq!(
|
||||
unicast(&http, &relay_url, &slow.public_hex(), &direct)
|
||||
.await
|
||||
.status(),
|
||||
reqwest::StatusCode::TOO_MANY_REQUESTS,
|
||||
"unicast to a lagging member must be visibly rejected"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
|
||||
Reference in New Issue
Block a user