Rust nos Workers: exemplos para rodar no seu Worker
O problema que isso resolve
Você tem biblioteca ou serviço em Rust e quer colocá-lo na borda, perto do usuário. Nos Workers, muita coisa quebrava. O Worker roda com uma única thread, dentro do ciclo de eventos do JavaScript, e o Tokio — o motor assíncrono mais usado no Rust — espera poder travar a thread e esperar (park) até um socket ficar legível ou um timer expirar. Os dois modelos não são compatíveis: uma espera bloqueante trava o loop de eventos compartilhado.
A saída foi um alvo de compilação novo: wasm32-unknown-emscripten no wasm-bindgen.
Passo a passo
1. Entenda quem faz o quê
O Emscripten é o tradutor: ele virtualiza arquivos, relógio e rede sobre as mesmas interfaces de Node.js que o Workers já suporta. O programa em Rust continua achando que está num computador comum; o tradutor converte cada pedido para o que o Workers entende. O trabalho juntou o time Portable Toolchains do Google e engenheiros da Cloudflare para que o wasm-bindgen funcionasse com esse alvo.
2. Escolha o exemplo mais próximo do seu caso
Há três exemplos publicados, do mais simples ao mais completo:
1. Workers em Rust com Emscripten
git clone --depth 1 https://github.com/cloudflare/workers-rs cd workers-rs/examples/emscripten
2. Tokio rodando dentro de um Worker
cd ../emscripten-tokio
3. Sockets TCP com Emscripten + Tokio
cd ../emscripten-tcp
3. Saiba qual problema de Tokio você vai encontrar
Para encaixar o Tokio em um host com ciclo de eventos, existem dois caminhos, e os dois estão implementados nos exemplos:
- JSPI (WebAssembly JavaScript Promise Integration): uma chamada bloqueante suspende a pilha do WebAssembly e devolve o controle ao loop de eventos — exatamente uma operação de park. O detalhe difícil é que o Rust não sabe que a própria pilha saiu de baixo dele: o contexto do runtime do Tokio vive em thread local, e troca de pilha não é troca de thread. A solução exige trocar esse contexto a cada entrada, saída, suspensão e retomada do JSPI — na prática, uma thread cooperativa multiplexada no tempo.
- LocalEventLoop (integração com o ciclo de eventos): o runtime do Tokio é dividido em duas partes. Em vez de esperar (park), ele apenas avisa o host que tem trabalho, e o host chama
drive()quando quiser rodar um lote de tarefas prontas.
let el = Builder::new_current_thread() .enable_all() .build_local_event_loop(Default::default(), host_waker)?;
el.spawn_local(async );
Com esse desenho o ciclo de eventos do host nunca fica bloqueado e se intercala com o Tokio, um lote por vez. A mesma arquitetura embute o runtime em um main loop de GTK, um message pump do Win32 ou um run loop do Cocoa. O preço: block_on não espera nesse modo — onde um runtime normal faria park, ele entra em pânico, porque nada poderia acordar aquela future de dentro da chamada.
4. Sockets: o que precisou ser construído
O Tokio constrói seu driver de I/O em cima de epoll_wait(), que o Emscripten não suportava (só poll() e uma emulação por WebSocket). Foram mais de 40 contribuições ao Emscripten para conectar sockets TCP, UDP e Unix. É o que permite dizer "conexão TCP de verdade dentro de um Worker" e não "emulação".
5. O teste que mostra o teto
Um servidor de Minecraft (Pumpkin) rodou dentro de um Durable Object, com entrada TCP, usando sockets TCP reais via Tokio. Cada arquivo salvo pelo jogo virou uma linha no SQLite do objeto — e o servidor reinicia no mesmo mundo. Foi portado por um engenheiro em um fim de semana.
libc, socket2, Mio) precisaram de patch — quase sempre só para permitir o novo alvo nas condições de plataforma.Limites e cuidados
- É prévia experimental. Ainda antes do lançamento oficial; parte das mudanças do Tokio aguarda aprovação upstream nas projetos originais.
- Os exemplos exigem os patches publicados pela Cloudflare enquanto a integração não chega às versões oficiais — não é só atualizar uma dependência.
- Uma thread, sem exceção. Tudo o que você escrever tem que conviver com o modelo cooperativo; código que assume paralelismo real não passa.
- Feedback é por canal aberto: issues no GitHub e o canal
#rust-on-workersno Discord da Cloudflare. Sem SLA de produto.
Por onde começar
Comece pela biblioteca que você já tem e que hoje vive presa a um servidor. Clone os exemplos, rode o emscripten puro primeiro (é o que menos exige), e só depois tente o emscripten-tokio — que é onde a assimetria de modelo aparece. Se a sua biblioteca não usa Tokio nem socket, provavelmente o primeiro exemplo responde a sua pergunta em uma tarde.
- Blog do anúncio: https://blog.cloudflare.com/rust-workers-emscripten-target/
- Exemplos: https://github.com/cloudflare/workers-rs/tree/main/examples
- Documentação do alvo Emscripten no wasm-bindgen: https://wasm-bindgen.github.io/wasm-bindgen/reference/emscripten.html