Deno Queues
(deno.com)- Deno Queues é uma fila distribuída serverless construída sobre o Deno KV, permitindo delegar tarefas demoradas para execução assíncrona ou agendar sua execução para um momento futuro
- Desenvolvedores só precisam inserir mensagens com
.enqueue()e processá-las com.listenQueue(), sem configurar nem manter uma infraestrutura de filas separada - Localmente, usa SQLite; no Deno Deploy, usa FoundationDB, e o Deploy inicia um V8 isolate sob demanda no momento de processar a mensagem
- O modelo de entrega é at-least-once delivery, portanto, em situações de falha ou nova tentativa, a mesma mensagem pode ser processada várias vezes
- Não há cobrança separada pela fila, mas enqueue conta como escrita no KV, e o recebimento de mensagens é contabilizado como escrita no KV e requisição do Deno Deploy; por isso, é preciso considerar tanto o processamento duplicado quanto a estrutura de custos
O que o Deno Queues faz
- Deno Queues é um recurso de filas baseado no Deno KV, que permite delegar parte do processamento de uma aplicação para tarefas assíncronas ou agendar tarefas para execução posterior
- O objetivo do Deno é reduzir configurações repetitivas e composição de infraestrutura no desenvolvimento de software em nuvem, oferecendo elementos básicos que permitam aos desenvolvedores projetar, melhorar e lançar mais rapidamente
- Deno KV é uma opção de persistência baseada em FoundationDB e atualmente está em beta aberto
- Queues oferece, sobre o Deno KV, mensageria escalável e gerenciamento de processamento em segundo plano
API básica e modelo de execução
- A API central do Deno Queues tem duas partes
.enqueue(): coloca uma nova mensagem na fila para ser entregue imediatamente ou em um momento futuro.listenQueue(): usado como handler que recebe e processa novas mensagens da fila
- O fluxo básico consiste em abrir o KV com
Deno.openKv(), enviar mensagens ao Slack emlistenQueuee definir{ delay: 60000 }emenqueuepara que o processamento aconteça 60 segundos depois - O armazenamento varia conforme o ambiente de execução
- Usa SQLite em execução local
- Usa FoundationDB ao executar no Deno Deploy
- No Deno Deploy, quando chega o momento em que uma mensagem pode ser processada, um V8 isolate é executado sob demanda e a mensagem é despachada
- O código da aplicação só precisa receber novas mensagens por meio do handler
listenQueue; o restante do gerenciamento de execução fica a cargo do Deno Deploy
Garantias de entrega e novas tentativas
- Deno Queues garante at-least-once delivery
- A maioria das mensagens enfileiradas chama o handler
listenQueueapenas uma vez, mas, em algumas situações de falha, o mesmo handler pode ser chamado várias vezes para garantir a entrega - Portanto, a aplicação deve lidar com processamento duplicado de mensagens de forma segura
- Se o handler
listenQueuelançar uma exceção, o runtime tentará automaticamente chamar novamente - As novas tentativas continuam até o sucesso ou até atingir o número máximo de tentativas; o valor máximo padrão atual é 5 vezes
- Mensagens que atingem o número máximo de tentativas são excluídas
Uso com KV atomic transactions
- Deno Queues pode ser combinado com KV atomic transactions
- Ao enfileirar uma mensagem como parte de uma transação KV, a mensagem só entra na fila se a transação inteira for bem-sucedida
- Um fluxo de exemplo verifica e atualiza os saldos de Bob e Liz e, em seguida, enfileira mensagens de notificação para ambos
- Verifica o estado com
check(bob, liz) - Reduz o saldo de Bob e aumenta o saldo de Liz
- Adiciona mensagens de notificação para Liz e Bob, respectivamente, com
enqueue commit()precisa ser bem-sucedido para que todas as alterações e o enqueue sejam refletidos
- Verifica o estado com
- Dentro do handler
listenQueue, também é possível atualizar o estado do Deno KV - Para executar atualizações por mensagem apenas uma vez, é possível configurar um fluxo de prevenção de processamento duplicado armazenando e removendo um nonce
- Armazena o nonce junto no momento do enqueue
- Durante o processamento, se o nonce não existir, retorna imediatamente
- Em caso de processamento bem-sucedido, exclui o nonce e atualiza conjuntamente o contador e o estado dos saldos
Casos de uso adequados para filas
- Filas são úteis para escalar aplicações, pois permitem que o servidor delegue processamento assíncrono e agende tarefas futuras
-
Notificações de e-mail agendadas
- Quando uma tarefa iniciada pelo usuário demora muito ou não exige aguardar uma resposta de conclusão, é possível delegá-la para a fila e manter a responsividade do servidor ou app
- No exemplo, a mensagem
welcome_emailé enfileirada imediatamente, e a mensagemsurvey_emailé executada com atraso usando{ delay: 259200000 }
-
Processamento confiável de webhooks
- Ao colocar uma requisição de webhook na fila em vez de processá-la imediatamente, é possível separar a resposta do processamento real
- Usando Oak junto com Queues, ao receber uma requisição POST em
/webhook, o corpo da requisição é colocado na fila e um HTTP 200 é retornado - O processamento real do webhook é feito de forma assíncrona em
listenQueuecomprocessWebHook
-
Bots para Slack e Discord
- Queues também pode ser usado para construir bots de Discord ou Slack
- O exemplo de app de lembretes para Slack é um caso de criação de um app simples de lembretes no Slack com Deno Queues
- O exemplo de bot para Discord usa Deno Queues para criar um giveaway e permitir que usuários participem com um único clique
- Mais exemplos de uso de filas podem ser encontrados em docs.deno.com
Modelo de cobrança
- Deno Queues não tem um item de cobrança dedicado separado
- O custo é calculado com base nas operações do Deno KV e nas requisições do Deno Deploy
- Enqueue de mensagem: cada operação de enqueue corresponde a 1 operação de escrita no KV
- Recebimento de mensagem: para cada mensagem recebida, são cobradas 1 escrita no KV e 1 tarifa de requisição
- A estrutura cobra apenas pelas operações utilizadas
Documentação e roadmap
- Documentação relacionada e referência da API
- Para criar apps web e servidores escaláveis, é necessária uma configuração que delegue tarefas em segundo plano para filas, mas a abordagem tradicional envolve muitas etapas de configuração
- Deno Queues é integrado ao runtime e funciona sobre a infraestrutura do Deno Deploy, permitindo usar uma fila distribuída serverless com poucas linhas de código
- Deno Queues é posicionado, junto com Deno KV, web standards APIs, npm e all-in-one modern tooling, como um componente para tornar o desenvolvimento web simples e produtivo
- Feedback e solicitações de recursos podem ser enviados pelo Discord ou pelas issues de deploy_feedback
1 comentários
Opiniões do Hacker News
Acabei de vasculhar por dentro a versão local em SQLite e organizei algumas anotações: https://til.simonwillison.net/deno/deno-kv#user-content-deno...
A parte mais interessante talvez seja o esquema usado para esse recurso:
CREATE TABLE queue ( ts integer not null, id text not null, data blob not null, backoff_schedule text not null, keys_if_undelivered blob not null, primary key (ts, id) );CREATE TABLE queue_running( deadline integer not null, id text not null, data blob not null, backoff_schedule text not null, keys_if_undelivered blob not null, primary key (deadline, id) );CREATE INDEX kv_expiration_ms_idx on kv (expiration_ms);Índices não foram projetados justamente para esse tipo de uso?
É algo bem novo, mas também um pouco inquietante. É claro que eles precisam comercializar, mas não precisava ser de uma forma totalmente fechada; talvez pudessem usar outra licença, como BSL ou PolyForm, na camada de expansão
Acho que a direção que o Deno está mirando aqui é bem voltada para o futuro
Comecei a usar Go este ano, e parte da linguagem é muito parecida com C. Além das diferenças em relação a C — por exemplo, graças ao garbage collection, ser possível retornar de uma função valores que parecem ponteiros alocados na stack —, recursos embutidos como
map[string]stringentram de forma natural. Se alguém criasse uma nova linguagem depois de 2023, eu sentiria que quase não faz sentido ela não ter uma sintaxe embutida para lidar com tipos de mapaEntão me parece lógico que um ecossistema centrado em servidores web tenha bibliotecas — e talvez algum dia até sintaxe da linguagem — para as funcionalidades primitivas que usamos com frequência. Não lembro do último projeto em que um servidor web distribuído não tivesse nem um armazenamento chave-valor para cache, nem um mecanismo de lock, nem mesmo uma fila temporária. Um sistema distribuído sem armazenamento chave-valor lembra vagamente uma linguagem de programação sem tipo de mapa, e é realmente uma tecnologia tipo canivete suíço
O problema potencial é que o Deno está seguindo esse caminho sozinho. É difícil ter certeza se os novos recursos que o Deno está adicionando também serão oferecidos por plataformas concorrentes e, mesmo que a API seja aberta como open source, ela fica no namespace
Deno, então não sei se simplesmente funcionaria quando eu quisesse trocar FoundationDB por Redis na AWSPor isso fico com a sensação de querer evitar o Deno. A sintaxe e as funcionalidades expostas são realmente atraentes, mas me preocupa ter de fazer uma grande cirurgia no código depois de ficar dependente, para torná-lo implantável em várias infraestruturas de nuvem. Muitos clientes exigem isso. Por exemplo, se um dia eu quiser vender para a Oracle ou a Salesforce e eles exigirem execução on-premises, vai sobrar para mim descobrir como adaptar o armazenamento chave-valor disponível do lado deles aos recursos do pacote
DenoÉ uma faca de dois gumes. O Deno pode conseguir empurrar essa visão para um público mais amplo, mas por enquanto acho que vou olhar com cautela
Dei uma testada rápida no
kv-connect-kit, uma implementação desse protocolo em TypeScript puro, e ele oferece uma API de cliente KV em qualquer runtime JavaScript. Isso inclui Cloudflare Workers, que não têm nenhum namespace DenoGitHub: https://github.com/skymethod/kv-connect-kit / npm: https://www.npmjs.com/package/kv-connect-kit / deno/x: https://deno.land/x/kv_connect_kit / demo: https://keyspace.deno.dev/
O protocolo parece funcionar como descrito, e escrever outros backends também parece bem simples
A indústria de tecnologia avançou bastante para sair de stacks com dependência de fornecedor, e isso, pelo contrário, lembra aqueles tempos
Não vejo qual é a diferença prática entre
Deno.KVfazer parte do runtime e adicionarimport KVno topo do arquivo. Com a segunda opção, você pode importar de onde quiser, seja no Deno ou em outro lugarE qual é a chance de a equipe do Deno oferecer bindings para outras linguagens além da própria? Se o Google começasse a colocar recursos primitivos nativos exclusivos do Google Cloud em Go, você chamaria isso de voltado para o futuro?
Ao mesmo tempo, a hospedagem própria deles também precisaria ser igual ou melhor que a dos líderes do setor. Outro caminho seria abandonar a hospedagem própria e oferecer uma solução multicloud com uma margem pequena em cima de adaptadores para parceiros de hospedagem. Assim o Deno não precisaria competir diretamente como provedor de hospedagem
Vejo isso menos como algo voltado para o futuro e mais como uma forma de monetizar o Deno como SaaS. É o que todo mundo no mundo JavaScript faz hoje com produtos de “cloud”: empacota um framework e revende AWS. Por isso existe uma tabela de preços
Se o KV do Deno depende do FoundationDB, também parece pouco provável que eles criem ativamente adaptadores para outros bancos de dados. Trocar a tecnologia de banco de dados é sempre algo grande, porque cada uma tem usos e características de desempenho diferentes
GC allowing one to return what look like stack allocated pointers from functionsnão me parece ser por causa do garbage collection, mas sim graças à análise de escape e ao SSANão acho muito convincente o argumento de que “para aproveitar a infraestrutura de nuvem pública, é preciso vasculhar código boilerplate e configurações complexas, o que consome muito tempo e energia dos desenvolvedores”
No fim das contas, estamos criando infraestrutura que precisa ser confiável. Gastar 30 minutos configurando uma tecnologia comprovada como filas SQS não parece pior do que confiar totalmente numa fila de brinquedo que o Deno criou “em cima de SQLite / FoundationDB”. O custo de 30 minutos de configuração e a “experiência do desenvolvedor” melhorada valem mesmo assumir esse risco? Para começo de conversa, com que frequência se configura uma fila?
Como programador por hobby, não uso muito grandes provedores como AWS ou Google, porque parecem bastante complexos. Talvez, quando se está acostumado, não seja tão ruim
Também quero manter cada projeto como um repositório independente no GitHub. Idealmente, qualquer outra pessoa deveria conseguir colocar uma aplicação web no ar com facilidade em um domínio separado, como se fosse sua própria aplicação web independente. É porque não quero ficar responsável pelos dados dos outros
Isso se parece, em certa medida, com o caso de uso do Sandstorm. Uma instrução de instalação do tipo “teste localmente e, se for usar de verdade, crie uma conta no Deno Deploy” soa bem razoável
Se alguém oferecer uma biblioteca equivalente para a nuvem, certamente haverá pessoas que a adotarão. No caso do Deno, parece que eles estão tentando identificar problemas comuns enfrentados pelos desenvolvedores do próprio ecossistema e resolvê-los empacotando uma solução razoável
Se você usa um motor de workflow que abstrai a fila, dá para “simplesmente escrever código” sem gerenciar tarefas, agendamentos, estado e tentativas
https://www.inngest.com/blog/how-durable-workflow-engines-wo...
Dito isso, sou autor de um motor de workflow, então tenho viés
Pela minha experiência anterior lidando com “semântica de entrega pelo menos uma vez” e “código de usuário”, usuários não entendem corretamente entrega pelo menos uma vez
No momento em que uma mensagem é reenviada, começam a chover reclamações de usuários e incidentes
Acho que ou se faz o quase impossível e se inventa semântica de entrega exatamente uma vez, ou então 0,1% de todas as mensagens deveriam ser sempre reenviadas, para impedir que os usuários passem a depender de que elas serão entregues apenas uma vez
Atualmente estou usando Deno Deploy e, para um projeto feito por uma pessoa só, o desempenho é excelente e é realmente simples
Tendo trabalhado com desenvolvimento em AWS em uma equipe grande, fico feliz com esse movimento de escapar da complexidade e conseguir colocar algo no ar facilmente sem pensar em configuração. O DNS também foi muito simples, e os certificados SSL automáticos foram ótimos. Não tenho nenhuma reclamação sobre o rumo que este produto está buscando, e estou ansioso pelo roadmap
A menos que eu tenha deixado passar algo, parece haver apenas uma fila por instância de
Deno.openKv()Na versão local, talvez dê para criar várias filas chamando
Deno.openKv("db-2.db")com um caminho de arquivo SQLite diferente a cada vez, mas isso parece ter um overhead grande para uma necessidade bastante comumTalvez esse seja o estilo de arquitetura do Deno. Ao criar uma aplicação complexa em Deno, será que a expectativa é uma estrutura no estilo microsserviços, com vários scripts funcionando juntos, cada um com seu próprio armazenamento KV e sua própria fila?
Um dos desenvolvedores principais confirmou isso no Discord: https://discord.com/channels/684898665143206084/115671428253...
Citando: “Correto. Atualmente só há suporte a uma única fila. No entanto, é possível multiplexar vários tipos de mensagens em uma única fila.”
Como fica o preço?
Eu pensava no Deno como uma espécie de substituto do Node.js; estou deixando passar alguma coisa? Dá para usar isso localmente ou em self-hosting sem custo?
Como “Queues are built on Deno KV”, a explicação é que localmente ele usa SQLite e, no Deno Deploy, usa FoundationDB para obter máxima disponibilidade e throughput
Escrevi um pouco mais sobre esse padrão aqui: https://til.simonwillison.net/deno/deno-kv
Se por acaso os desenvolvedores estiverem vendo isto, acho que a controle de acesso na excelente usabilidade atual do KV pode acabar causando dor mais adiante
Fico curioso se a solução é simplesmente “implemente você mesmo no espaço do usuário e não crie bugs”, ou se há algo planejado
O suporte recente a Jupyter e agora esse recurso de filas me deixam animado. São coisas realmente muito legais
Mas acho que não escreveria um servidor em Deno para colocá-lo em produção no meu próprio servidor. Não gosto de serverless
O modelo de negócios do Deno e do Bun é construído em torno de serverless, ou seja, Deno Deploy. E o Deno Deploy é mais um runtime
Isso fica claro no KV e nas filas. Localmente ou em self-hosting, você acaba com uma versão que mal funciona, montada sobre outras tecnologias
Ou seja, você estaria fazendo self-hosting de uma versão do Deno diferente daquela usada pela maioria dos clientes do Deno
Quantas pessoas usam Deno para rodar servidores em seu próprio hardware? Se esse número for pequeno, eu preferiria usar Node
O Deno é realmente interessante. É ótimo por ter um modelo de negócios viável, boa usabilidade e não exigir tarefas inúteis de configuração
O Deno em si é, essencialmente, Node.js com compilação automática de TypeScript. Originalmente, isso só exigiria um arquivo de configuração a mais. Quando o projeto foi lançado, ele destacava bastante a ideia de escapar do ecossistema bagunçado do NPM, mas no fim teve que voltar atrás e adicionar suporte ao NPM, e esse diferencial também desapareceu
O Deno Deploy é igual às dezenas de serviços do tipo Lambda que já existem. O armazenamento KV e, agora, as filas equivalem a Redis, LevelDB, RocksDB, Dynamo, SQS ou inúmeras opções semelhantes. Ainda não vi nenhum recurso que realmente diferencie o Deno dos demais
Se você prefere que uma única empresa cuide do runtime da linguagem, da hospedagem de computação e do armazenamento de dados, isso pode ser atraente. Mas, pessoalmente, eu preferiria evitar, especialmente se essa empresa não tiver histórico nessa área