Melhores Práticas Assíncronas
Regras para serviços Rust assíncronos responsivos - I/O não bloqueante, concorrência estruturada e limites honestos do runtime.
Como Usar Esta Lista
- Aplique antes de enviar serviços Axum/Tokio para produção.
- Use como uma rubrica de PR para novos endpoints assíncronos e workers de background.
- Combine com testes de carga e
tokio-consolequando a latência regredir.
A - Runtime e Estrutura
- Bibliotecas expõem
async fn; binários possuem#[tokio::main]. Um runtime por processo. - Prefira drivers assíncronos nativos (tokio, sqlx, reqwest). Evite
spawn_blockingcomo padrão. - Ajuste
worker_threadsapós medição. Mais threads não é escalabilidade gratuita. - Use
current_threadapenas para testes ou!Send+LocalSet. Servidores usammulti_thread. - Documente MSRV e a escolha do runtime no README. O onboarding depende disso.
B - Disciplina Não Bloqueante
- Nunca use
std::thread::sleepou I/O síncrono em threads de worker. Usetokio::time::sleepetokio::fs. - Descarregue CPU e SDKs legados com
spawn_blocking. Limite a concorrência com semáforos. - Nunca mantenha
std::sync::MutexGuardatravés de.await. Usetokio::sync::Mutexou escopos curtos. - Envolva Rayon/
par_iteremspawn_blocking. Não bloqueie workers em seções paralelas. - Defina timeouts de cliente nas camadas de conexão, requisição e ociosa. Peers travados consomem recursos.
C - Tarefas e Concorrência
- Prefira
join!para awaits independentes em uma tarefa. Usespawnquando lifetimes ou isolamento de CPU exigirem. - Use loops
select!com branches cancel-safe. Documente quais métodos são cancel-safe. - Propague o desligamento via
CancellationTokenouwatch. Não confie apenas no kill do processo. - Await ou aborte todo
JoinHandle. Sem tarefas de background vazando após erros. - Limite o fan-out com semáforos. Proteja peers, FDs e slots de pool de banco de dados.
D - Estado e Tipos
- Compartilhe o estado do aplicativo com
Arc+ clones baratos. Pool de banco de dados, cliente HTTP, snapshots de configuração. - Prefira passagem de mensagens (canais) em vez de
Arc<Mutex<App>>. Use Actors para estado mutável complexo. - Garanta que as tarefas spawnadas sejam
Sendem runtime multi-thread. SemRcatravés de await em trabalho spawnado. - Use
async-traitou traits async nativas intencionalmente. Conheça os trade-offs de dyn vs genérico. - Valide erros nas fronteiras com
Resulttipado. Mapeie para respostas HTTP/problema estáveis.
E - Operações
- Instrumente com spans
tracingpor requisição e tarefa. Inclua IDs de trace através de await. - Teste de carga de desligamento gracioso e desconexão de cliente. Handlers cancelam cooperativamente.
- Monitore a profundidade da fila do pool de bloqueio. Sinal de regressão para chamadas síncronas em caminhos assíncronos.
- Teste com
#[tokio::test]etime::pause. Testes de timeout determinísticos. - Revise ilhas síncronas quando dependências lançarem async. Remova pontes de executor quando possível.
FAQs
Async é sempre mais rápido?
Não - apenas quando muitos waits de I/O concorrentes compartilham poucas threads. Tarefas CPU-bound ou com baixa concorrência podem se beneficiar de threads síncronas.
Maior erro em produção?
Bloquear threads de worker com I/O síncrono ou loops de CPU - causa picos de latência de cauda sob carga.
Padrão Axum + sqlx?
Arc<PgPool> no estado, handlers async, timeouts em queries, migrações offline.
Quando usar spawn vs join?
join! para awaits paralelos coordenados; spawn para fire-and-forget ou workers de longa duração com rastreamento de JoinHandle.
Desconexão do cliente?
O future do handler descartado cancela o trabalho - torne os efeitos colaterais idempotentes ou mova commits críticos para fora da seção cancelável.
Async single-threaded?
Válido para embarcados ou futures !Send - não típico para servidores de API multi-core.
Tratamento de erros?
thiserror em bibliotecas, anyhow em binários; nunca ignore erros em tarefas spawnadas.
Backpressure?
Canais limitados, semáforos em chamadas de saída, HTTP 503 quando sobrecarregado - filas ilimitadas escondem falhas até OOM.
Estratégia de testes?
Teste unitário de lógica pura síncrona; teste de integração de handlers com reqwest contra axum::Router em #[tokio::test].
Primeiro refactor para código síncrono legado?
Identifique as 3 principais chamadas bloqueantes no caminho quente; substitua por async ou spawn_blocking com limite.
Relacionado
- Noções Básicas de Async - para começar
- Bloqueio em Async - guia de descarregamento
- Cancelamento e Timeouts - prazos
- Melhores Práticas de Concorrência - regras de thread
- Melhores Práticas do Tokio - ajuste do runtime
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.