Filas e tarefas em segundo plano em Rust: escrevendo um worker assíncrono em uma hora
\n\nVocê já se perguntou por que seu serviço web às vezes "trava" quando o usuário clica no botão "Enviar"? Na maioria das vezes, a culpa é de operações pesadas que são executadas durante o processamento da requisição. Envio de email, geração de PDF, processamento de imagens, integração com APIs externas — tudo isso deve viver sua própria vida, e não bloquear a resposta ao usuário. A solução são filas e tarefas em segundo plano.
\n\nE se você está acostumado a resolver esse problema em Python com Celery ou RQ, em Rust você terá uma surpresa. Rust não é apenas rápido — ele oferece um controle único sobre memória e threads, permitindo escrever workers supereficientes que consomem o mínimo de recursos. Neste artigo, vamos analisar como implementar filas e tarefas em segundo plano em Rust, usando bibliotecas e abordagens modernas. Você aprenderá como construir um sistema confiável de processamento de tarefas que não cairá sob carga.
\n\nPor que Rust para tarefas em segundo plano? Três vantagens não óbvias
\n\nAntes de mergulharmos no código, vamos entender por que usar Rust para filas, quando existem soluções testadas em Python.
\n\n- \n
- Desempenho sem GC (coletor de lixo). Workers em Python podem "congelar" nas pausas do coletor de lixo. Rust não tem esse problema — você controla cada byte de memória. Isso é crítico para sistemas de alta carga, onde cada milissegundo importa. \n
- Assincronicidade "nativa". Rust com
tokioouasync-stdpermite processar milhares de conexões simultâneas em uma única thread. Você pode executar centenas de workers sem medo de estouro de memória. \n - Confiabilidade. O sistema de ownership (propriedade) em Rust garante que você não terá condições de corrida (data race) em um worker em segundo plano. Erros são tratados explicitamente — sem exceções ocultas. \n
Agora que entendemos o "porquê", vamos para o "como".
\n\nEscolhendo o broker de mensagens: RabbitMQ vs Redis vs NATS
\n\nUma fila de tarefas não é apenas uma lista. É um broker de mensagens que armazena tarefas e as distribui entre os workers. No ecossistema Rust, existem crates para todos os brokers populares.
\n\nRabbitMQ + lapin: o clássico no mundo das filas
\n\nRabbitMQ é um monstro confiável para tarefas enterprise. A crate lapin fornece uma API assíncrona limpa. É ideal se você precisa de roteamento de mensagens, garantias de entrega e topologias complexas.
Redis + fred: simplicidade e velocidade
\n\nRedis é um canivete suíço. Com fred (cliente Redis assíncrono), você pode criar uma fila usando listas (BLPOP) ou Pub/Sub. Redis é ótimo para cenários simples: "enviou tarefa — recebeu resultado".
NATS + async-nats: broker leve
\n\nNATS é um broker de nuvem com latência mínima. Se você precisa processar milhões de mensagens por segundo em instâncias pequenas, NATS é sua escolha.
\n\nNeste artigo, vamos nos concentrar no RabbitMQ, pois ele oferece o controle mais completo. Mas os princípios serão os mesmos para qualquer broker.
\n\nEscrevendo uma fila em Rust: exemplo passo a passo
\n\nVamos criar um sistema simples: um gerador de tarefas (producer) e um worker (consumer). Processaremos tarefas de envio de email.
\n\nPasso 1: Configuração do projeto e dependências
\n\nCrie um novo projeto:
\n\ncargo new rust_queue_demo\ncd rust_queue_demo\n\nAdicione as dependências no Cargo.toml:
[dependencies]\ntokio = { version = "1", features = ["full"] }\nlapin = "2.4"\nserde = { version = "1", features = ["derive"] }\nserde_json = "1"\ntracing = "0.1"\ntracing-subscriber = "0.3"\nanyhow = "1"\n\nUsamos tokio como runtime assíncrono, lapin para RabbitMQ, serde para serialização de tarefas e tracing para logging.