IngenieríaMar 28, 2026
Deep EVM #24: Propagación de Contexto en Rust Asíncrono — Deadlines, Cancelación y Tracing
OS
Open Soft Team
Engineering Team
El problema del contexto en async Rust
En Go, el paquete context propaga deadlines, cancelación y valores a través de la cadena de llamadas. Rust no tiene un equivalente estándar, pero podemos construir patrones similares con tokio.
Deadlines con tokio::time::timeout
use tokio::time::{timeout, Duration};
async fn process_block(block: Block) -> Result<Vec<Bundle>> {
// Deadline total: 10 segundos
let result = timeout(
Duration::from_secs(10),
process_block_inner(block)
).await;
match result {
Ok(Ok(bundles)) => Ok(bundles),
Ok(Err(e)) => Err(e),
Err(_) => {
tracing::warn!("Block processing timed out");
Ok(vec![]) // Retornar vacío en timeout
}
}
}
Cancelación cooperativa con CancellationToken
use tokio_util::sync::CancellationToken;
async fn worker(token: CancellationToken) {
loop {
tokio::select! {
_ = token.cancelled() => {
tracing::info!("Worker cancelado");
return;
}
result = do_work() => {
handle_result(result);
}
}
}
}
// Uso:
let token = CancellationToken::new();
let child_token = token.child_token();
tokio::spawn(worker(child_token));
// Cancelar todos los workers:
token.cancel();
Propagación de trace IDs
Para correlacionar logs a través de componentes async:
use tracing::{instrument, Span};
use uuid::Uuid;
#[instrument(fields(request_id = %Uuid::new_v4()))]
async fn handle_request(req: Request) -> Response {
let result = process(req).await; // Hereda el span
respond(result).await // También hereda
}
Struct de contexto personalizado
struct PipelineContext {
deadline: Instant,
cancellation: CancellationToken,
trace_id: String,
block_number: u64,
}
impl PipelineContext {
fn remaining(&self) -> Duration {
self.deadline.saturating_duration_since(Instant::now())
}
fn is_expired(&self) -> bool {
Instant::now() >= self.deadline
}
}
Este contexto se pasa a cada etapa del pipeline, permitiendo cancelación temprana y seguimiento distribuido.
Conclusión
La propagación de contexto en Rust asíncrono requiere composición manual de timeout, CancellationToken y tracing spans. Aunque no es tan integrado como el context.Context de Go, los patrones resultantes son más explícitos y tipo-seguros.
Etiquetas