refactor: extract runtime state backends

This commit is contained in:
fawney19
2026-05-08 00:18:12 +08:00
parent 6f620d92be
commit 6247ac3edc
111 changed files with 4358 additions and 3203 deletions

View File

@@ -8,6 +8,7 @@ description = "Tunnel proxy for Aether"
aether-contracts.workspace = true
aether-http.workspace = true
aether-runtime.workspace = true
aether-runtime-state.workspace = true
tokio = { version = "1", features = ["full"] }
reqwest.workspace = true
hyper = { version = "1", features = ["client", "http1", "http2"] }

View File

@@ -6,10 +6,8 @@ use std::sync::{Arc, RwLock};
use std::time::{Duration, Instant};
use aether_http::{jittered_delay_for_retry, HttpRetryConfig};
use aether_runtime::{
init_reloadable_service_tracing, wait_for_shutdown_signal, ConcurrencyGate,
DistributedConcurrencyGate, RedisDistributedConcurrencyConfig,
};
use aether_runtime::{init_reloadable_service_tracing, wait_for_shutdown_signal, ConcurrencyGate};
use aether_runtime_state::{RedisClientConfig, RuntimeSemaphoreConfig, RuntimeState};
use arc_swap::ArcSwap;
use tokio::sync::{watch, Mutex};
use tokio::task::JoinHandle;
@@ -225,12 +223,18 @@ pub async fn run(mut config: Config, servers: Vec<ServerEntry>) -> anyhow::Resul
.distributed_stream_redis_url
.clone()
.expect("distributed stream redis url should be validated");
let distributed_gate = DistributedConcurrencyGate::new_redis(
"proxy_streams_distributed",
limit,
RedisDistributedConcurrencyConfig {
let runtime = RuntimeState::redis(
RedisClientConfig {
url: redis_url,
key_prefix: state.config.distributed_stream_redis_key_prefix.clone(),
},
Some(state.config.distributed_stream_command_timeout_ms),
)
.await?;
let distributed_gate = runtime.semaphore(
"proxy_streams_distributed",
limit,
RuntimeSemaphoreConfig {
lease_ttl_ms: state.config.distributed_stream_lease_ttl_ms,
renew_interval_ms: state.config.distributed_stream_renew_interval_ms,
command_timeout_ms: Some(state.config.distributed_stream_command_timeout_ms),

View File

@@ -4,10 +4,8 @@ use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, RwLock};
use std::time::Duration;
use aether_runtime::{
AdmissionPermit, ConcurrencyError, ConcurrencyGate, ConcurrencySnapshot,
DistributedConcurrencyError, DistributedConcurrencyGate, DistributedConcurrencySnapshot,
};
use aether_runtime::{AdmissionPermit, ConcurrencyError, ConcurrencyGate, ConcurrencySnapshot};
use aether_runtime_state::{RuntimeSemaphore, RuntimeSemaphoreError, RuntimeSemaphoreSnapshot};
use crate::config::Config;
use crate::registration::client::AetherClient;
@@ -27,7 +25,7 @@ pub struct AppState {
/// Optional per-process stream admission gate.
pub stream_gate: Option<Arc<ConcurrencyGate>>,
/// Optional cross-instance stream admission gate.
pub distributed_stream_gate: Option<Arc<DistributedConcurrencyGate>>,
pub distributed_stream_gate: Option<Arc<RuntimeSemaphore>>,
}
/// Per-server state: one instance per Aether server connection.
@@ -103,10 +101,7 @@ impl AppState {
self
}
pub fn with_distributed_stream_concurrency_gate(
mut self,
gate: Arc<DistributedConcurrencyGate>,
) -> Self {
pub fn with_distributed_stream_concurrency_gate(mut self, gate: Arc<RuntimeSemaphore>) -> Self {
self.distributed_stream_gate = Some(gate);
self
}
@@ -117,7 +112,7 @@ impl AppState {
pub async fn distributed_stream_concurrency_snapshot(
&self,
) -> Result<Option<DistributedConcurrencySnapshot>, DistributedConcurrencyError> {
) -> Result<Option<RuntimeSemaphoreSnapshot>, RuntimeSemaphoreError> {
match &self.distributed_stream_gate {
Some(gate) => gate.snapshot().await.map(Some),
None => Ok(None),
@@ -150,10 +145,10 @@ impl AppState {
let distributed = match &self.distributed_stream_gate {
Some(gate) => Some(gate.try_acquire().await.map_err(|err| {
match err {
DistributedConcurrencyError::Saturated { gate, limit } => {
RuntimeSemaphoreError::Saturated { gate, limit } => {
ProxyAdmissionError::Saturated { gate, limit }
}
DistributedConcurrencyError::Unavailable {
RuntimeSemaphoreError::Unavailable {
gate,
limit,
message,
@@ -162,7 +157,7 @@ impl AppState {
limit,
message,
},
DistributedConcurrencyError::InvalidConfiguration(message) => {
RuntimeSemaphoreError::InvalidConfiguration(message) => {
ProxyAdmissionError::Unavailable {
gate: "proxy_streams_distributed",
limit: self

View File

@@ -1515,7 +1515,10 @@ mod tests {
use std::sync::{Mutex, Once};
use std::task::{Context, Poll};
use aether_runtime::{ConcurrencyGate, DistributedConcurrencyGate};
use aether_runtime::ConcurrencyGate;
use aether_runtime_state::{
MemoryRuntimeStateConfig, RuntimeSemaphore, RuntimeSemaphoreConfig, RuntimeState,
};
use arc_swap::ArcSwap;
use axum::body::Body;
use axum::http::{header, HeaderMap, Response, StatusCode};
@@ -2206,10 +2209,15 @@ mod tests {
#[tokio::test]
async fn rejects_stream_when_distributed_admission_gate_is_saturated() {
let gate = Arc::new(DistributedConcurrencyGate::new_in_memory(
"proxy_streams_distributed",
1,
));
let gate = Arc::new(
RuntimeState::memory(MemoryRuntimeStateConfig::default())
.semaphore(
"proxy_streams_distributed",
1,
RuntimeSemaphoreConfig::default(),
)
.expect("distributed semaphore"),
);
let _permit = gate.try_acquire().await.expect("first permit");
let state = sample_state(None, Some(gate));
let server = sample_server(&state);
@@ -2264,7 +2272,7 @@ mod tests {
fn sample_state(
stream_gate: Option<Arc<ConcurrencyGate>>,
distributed_stream_gate: Option<Arc<DistributedConcurrencyGate>>,
distributed_stream_gate: Option<Arc<RuntimeSemaphore>>,
) -> Arc<AppState> {
ensure_rustls_provider();
let config = Arc::new(sample_config());