Uma biblioteca leve e eficiente para orquestração de eventos assíncronos em Golang.
- ✅ Type-Safe com Generics - Zero type assertions, compile-time safety!
- ✅ Worker Pool - Pool configurável de goroutines para processar eventos
- ✅ Event Queue - Fila interna com buffer usando channels nativos do Go
- ✅ Retry Logic - Reprocessamento automático em caso de falha
- ✅ Dead Letter Queue (DLQ) - Eventos que falharam após todas as tentativas
- ✅ Priority Events - Suporte para eventos com prioridade
- ✅ Graceful Shutdown - Encerramento seguro aguardando processar eventos pendentes
- ✅ Thread-Safe - Totalmente seguro para uso concorrente
- ✅ Context Support - Timeout e cancelamento via context
go get github.com/thiagozs/go-eventbuspackage main
import (
"context"
"fmt"
"eventbus"
)
// Define suas structs tipadas
type UserCreatedEvent struct {
UserID string
Email string
Name string
}
func main() {
// Configuração
config := eventbus.Config{
Workers: 5,
QueueSize: 100,
Retries: 3,
}
bus := eventbus.NewEventBus(config)
// Registra handler TIPADO - sem type assertions!
eventbus.Subscribe(bus, "user.created", func(ctx context.Context,
event eventbus.Event[UserCreatedEvent]) error {
// Acesso direto aos campos tipados
fmt.Printf("Novo usuário: %s (%s)\n", event.Payload.Name, event.Payload.Email)
return nil
})
// Publica evento com struct tipada
eventbus.Publish(bus, "user.created", UserCreatedEvent{
UserID: "123",
Email: "joao@example.com",
Name: "João Silva",
})
// Shutdown graceful
bus.Shutdown(5 * time.Second)
}type Config struct {
Workers int // Número de workers (default: 10)
QueueSize int // Tamanho do buffer (default: 100)
Retries int // Tentativas extras após falha (default: 3)
// Total = 1 inicial + Retries
// Ex: Retries=3 → 4 tentativas no total
DLQSize int // Tamanho da DLQ (default: 50)
WorkerTimeout time.Duration // Timeout por evento (default: 30s)
}Antes (sem generics):
bus.Subscribe("user.created", func(ctx context.Context,
event eventbus.Event) error {
// Precisa fazer type assertion manual
payload := event.Payload.(map[string]interface{})
email := payload["email"].(string) // Pode quebrar em runtime!
return nil
})Agora (com generics):
type UserCreatedEvent struct {
Email string
Name string
}
eventbus.Subscribe(bus, "user.created", func(ctx context.Context,
event eventbus.Event[UserCreatedEvent]) error {
// Type-safe! Autocomplete funciona!
email := event.Payload.Email // Compile-time safety!
return nil
})// Evento normal (prioridade 0)
eventbus.Publish(bus, "notification.email",
EmailData{To: "user@example.com"})
// Evento urgente (prioridade alta)
eventbus.PublishWithPriority(bus, "alert.critical",
AlertData{Level: "CRITICAL"}, 10)// Diferentes handlers para o mesmo tipo de evento
eventbus.Subscribe(bus, "order.created", sendEmailHandler)
eventbus.Subscribe(bus, "order.created", updateInventoryHandler)
eventbus.Subscribe(bus, "order.created", notifyWarehouseHandler)
// Todos recebem o mesmo evento tipado!go func() {
dlq := bus.GetDLQ()
for wrapper := range dlq {
dlqEvent := eventbus.GetDLQEvent(wrapper)
log.Printf("Evento falhou: %s - %+v", dlqEvent.Type, dlqEvent.Payload)
// Aqui você pode: salvar em DB, enviar alerta, etc
}
}()stats := bus.Stats()
fmt.Printf("Handlers: %v\n", stats["handlers_registrados"])
fmt.Printf("Queue: %v/%v\n", stats["queue_size"], config.QueueSize)┌─────────────┐
│ Publisher │
└──────┬──────┘
│ Publish()
▼
┌─────────────────┐
│ Event Queue │ (buffered channel)
└────────┬────────┘
│
┌────┴────┐
▼ ▼
┌────────┐ ┌────────┐
│Worker 1│ │Worker N│ (goroutines)
└────┬───┘ └───┬────┘
│ │
▼ ▼
┌──────────────────┐
│ Handlers │
└────────┬─────────┘
│
┌────┴────┐
│ │
▼ ▼
Success Fail → Retry → DLQ
- Microserviços - Comunicação assíncrona entre serviços
- Webhooks - Processar webhooks de forma escalável
- Background Jobs - Tarefas assíncronas (emails, notificações, etc)
- Event Sourcing - Arquitetura baseada em eventos
- CQRS - Separação de comandos e queries
- Workers processam eventos em paralelo
- Channels nativos do Go (super eficientes!)
- Zero alocações extras na maioria dos casos
- Backpressure automático quando queue está cheia
- Handler falha → Retry com backoff exponencial
- Tentativa inicial (imediata)
- Retry 1: aguarda 1s
- Retry 2: aguarda 2s
- Retry N: aguarda Ns
- Após todas tentativas → Envia para DLQ
- DLQ cheia → Log de erro (evento é perdido)
Exemplo: Com Retries: 3, cada evento terá 4 tentativas totais (1 inicial + 3 retries).
// Aguarda até 10s para processar eventos pendentes
if err := bus.Shutdown(10 * time.Second); err != nil {
log.Fatal("Timeout no shutdown!")
}✅ Use context nos handlers para timeout/cancelamento
✅ Mantenha handlers rápidos (< 1s idealmente)
✅ Configure workers baseado na carga esperada
✅ Monitore a DLQ para identificar problemas
✅ Use eventos com prioridade para casos críticos
✅ Sempre faça shutdown graceful em produção
Pull requests são bem-vindos! Para mudanças grandes, abra uma issue primeiro.
Este projeto é distribuído sob a licença MIT. Consulte o arquivo LICENSE para obter detalhes.
2025, Thiago Zilli Sarmento ❤️