Eventos
Eventos são a forma que os serviços têm de se comunicar sem se conhecerem diretamente. Em vez de ServicoA chamar ServicoB diretamente, ele emite um evento. Qualquer serviço que quiser reagir escuta esse evento.
Isso é chamado de arquitetura orientada a eventos — e em Jade DSL, é parte da linguagem, não uma biblioteca externa.
Declarando um evento
evento ProdutoCriado
produtoId: id
nome: texto
categoria: texto
fimUm evento é uma estrutura de dados simples — campos que carregam as informações sobre o que aconteceu.
Emitindo um evento
Use emitir seguido do nome do evento e seus valores:
servico ProdutoService
funcao criar(nome: texto, categoria: texto) -> Produto
p = Produto()
p.nome = nome
p.categoria = categoria
salvar p
emitir ProdutoCriado(p.id, p.nome, p.categoria)
retornar p
fim
fimA ordem dos argumentos segue a ordem dos campos na declaração do evento.
Escutando um evento
Use escutar dentro de um serviço:
servico NotificacaoService
escutar ProdutoCriado
Console.escrever("Novo produto: " + nome + " (categoria: " + categoria + ")")
enviarNotificacaoAdmin(produtoId)
fim
fimDentro do bloco escutar, os campos do evento ficam disponíveis diretamente como variáveis.
O poder do desacoplamento
Considere este sistema:
// === Declaração dos eventos ===
evento PedidoRealizado
pedidoId: id
clienteId: id
valorTotal: decimal
fim
evento EstoqueBaixo
produtoId: id
estoqueAtual: numero
fim
// === Serviço de pedidos — não sabe quem vai reagir ===
servico PedidoService
funcao realizar(clienteId: id, itens: lista<ItemDados>) -> Pedido
pedido = Pedido()
pedido.clienteId = clienteId
pedido.valorTotal = calcularTotal(itens)
pedido.status = StatusPedido.PENDENTE
salvar pedido
emitir PedidoRealizado(pedido.id, clienteId, pedido.valorTotal)
retornar pedido
fim
fim
// === Serviços que reagem — independentes entre si ===
servico NotificacaoService
escutar PedidoRealizado
cliente = EntityManager.buscarPorId(Cliente, clienteId)
enviarEmailConfirmacao(cliente.email, pedidoId, valorTotal)
fim
fim
servico RelatorioService
escutar PedidoRealizado
registrarVenda(pedidoId, valorTotal)
atualizarMetricasDiarias()
fim
fim
servico FidelidadeService
escutar PedidoRealizado
adicionarPontos(clienteId, valorTotal)
fim
fimPedidoService emitiu um único evento. Três serviços diferentes reagiram. Nenhum deles sabe da existência dos outros.
Eventos com muitos campos
evento FaturaEmitida
faturaId: id
pedidoId: id
clienteId: id
valor: decimal
vencimento: data
status: texto
fim
servico FaturaService
funcao gerarFatura(pedidoId: id) -> Fatura
pedido = EntityManager.buscarPorId(Pedido, pedidoId)
fatura = Fatura()
fatura.pedidoId = pedidoId
fatura.clienteId = pedido.clienteId
fatura.valor = pedido.valorTotal
fatura.vencimento = DateTime.add(DateTime.today(), 30, "days")
fatura.status = "pendente"
salvar fatura
emitir FaturaEmitida(fatura.id, pedidoId, pedido.clienteId, pedido.valorTotal, fatura.vencimento, "pendente")
retornar fatura
fim
fimDetectando ciclos de eventos
O compilador detecta automaticamente ciclos de eventos — situações onde um evento A dispara B, que dispara A novamente (loop infinito):
servico ServicoA
escutar EventoX
emitir EventoY(dados) // A escuta X e emite Y
fim
fim
servico ServicoB
escutar EventoY
emitir EventoX(dados) // B escuta Y e emite X — CICLO!
fim
fim
// ERRO DE COMPILAÇÃO:
// Ciclo de eventos detectado: EventoX → EventoY → EventoXIsso é uma proteção importante — o compilador impede loops infinitos de eventos antes de o código rodar.
Padrões comuns com eventos
Auditoria automática
evento AcaoRealizada
usuarioId: id
acao: texto
tipoEntidade: texto
entidadeId: id
detalhes: texto
fim
servico AuditoriaService
escutar AcaoRealizada
log = LogAuditoria()
log.usuarioId = usuarioId
log.acao = acao
log.tipoEntidade = tipoEntidade
log.entidadeId = entidadeId
log.detalhes = detalhes
log.realizadoEm = DateTime.now()
salvar log
fim
fim
// Qualquer serviço emite quando faz algo importante
servico ProdutoService
funcao excluir(produtoId: id)
produto = EntityManager.buscarPorId(Produto, produtoId)
produto.ativo = falso
salvar produto
emitir AcaoRealizada(sessaoAtual.usuarioId, "exclusao", "Produto", produtoId, "Produto '" + produto.nome + "' desativado")
fim
fimCache invalidado
evento DadosAlterados
tabela: texto
registroId: id
fim
servico CacheService
escutar DadosAlterados
chave = tabela + "_" + registroId
Cache.invalidar(chave)
Console.escrever("Cache invalidado: " + chave)
fim
fimReprocessamento em falha
evento ProcessamentoFalhou
operacaoId: id
motivo: texto
tentativa: numero
fim
servico RetryService
escutar ProcessamentoFalhou
se tentativa < 3
Console.escrever("Tentativa " + tentativa + " falhou. Reagendando...")
reprocessar(operacaoId, tentativa + 1)
senao
Console.escrever("ERRO: Operação falhou após 3 tentativas: " + operacaoId)
emitir OperacaoAbortada(operacaoId, motivo)
fim
fim
fimResumo
| Keyword | O que faz |
|---|---|
evento Nome | Declara um tipo de evento com seus campos |
emitir Nome(v1, v2...) | Dispara o evento com os valores |
escutar Nome | Reage ao evento (campos disponíveis como variáveis) |