Especialização em Backend com Go & Gin • Demonstrações Práticas Compiláveis


💻 Código de Exemplo 01 — Domínio e Pipeline de Ingestão Assíncrona em Lote

package domain

import "time"

// PedidoAltaVazao é a entidade de domínio: sem tags gin, sem SQL, sem
// dependência de framework — apenas a regra de negócio pura.
type PedidoAltaVazao struct {
	ID        uint      `json:"id"`
	ClienteID uint      `json:"cliente_id"`
	Valor     float64   `json:"valor"`
	Status    string    `json:"status"`
	CriadoEm  time.Time `json:"criado_em"`
}

func NovoPedido(clienteID uint, valor float64) PedidoAltaVazao {
	return PedidoAltaVazao{
		ClienteID: clienteID,
		Valor:     valor,
		Status:    "recebido",
		CriadoEm:  time.Now().UTC(),
	}
}
package usecase

import (
	"log"
	"sync"
	"time"

	"meuservico/domain"
)

// PersistidorLote é a única dependência externa do ingestor — implementada
// pela camada repository (GORM), mantendo o usecase agnóstico de banco.
type PersistidorLote interface {
	SalvarLote(pedidos []domain.PedidoAltaVazao) error
}

// BatchIngestor absorve picos de tráfego em um canal bufferizado e persiste
// em lote por gatilho duplo: tamanho do lote OU intervalo de tempo, o que
// vier primeiro — evita tanto sobrecarga do banco quanto dados "presos".
type BatchIngestor struct {
	canal          chan domain.PedidoAltaVazao
	persistidor    PersistidorLote
	tamanhoMaximo  int
	intervaloFlush time.Duration
	wg             sync.WaitGroup
}

func NovoIngestor(p PersistidorLote, bufferSize, tamanhoLote int, flush time.Duration) *BatchIngestor {
	return &BatchIngestor{
		canal:          make(chan domain.PedidoAltaVazao, bufferSize),
		persistidor:    p,
		tamanhoMaximo:  tamanhoLote,
		intervaloFlush: flush,
	}
}

// Ingerir enfileira um evento sem bloquear o handler HTTP (desde que o
// buffer não esteja saturado); retorna erro se o canal estiver cheio,
// permitindo que o handler responda 503 em vez de travar indefinidamente.
func (b *BatchIngestor) Ingerir(p domain.PedidoAltaVazao) error {
	select {
	case b.canal <- p:
		return nil
	default:
		return ErrBufferCheio
	}
}

func (b *BatchIngestor) IniciarProcessadorLote() {
	b.wg.Add(1)
	go func() {
		defer b.wg.Done()
		lote := make([]domain.PedidoAltaVazao, 0, b.tamanhoMaximo)
		ticker := time.NewTicker(b.intervaloFlush)
		defer ticker.Stop()

		for {
			select {
			case evento, ok := <-b.canal:
				if !ok {
					b.flush(&lote)
					return
				}
				lote = append(lote, evento)
				if len(lote) >= b.tamanhoMaximo {
					b.flush(&lote)
				}
			case <-ticker.C:
				b.flush(&lote)
			}
		}
	}()
}

func (b *BatchIngestor) flush(lote *[]domain.PedidoAltaVazao) {
	if len(*lote) == 0 {
		return
	}
	if err := b.persistidor.SalvarLote(*lote); err != nil {
		log.Printf("erro ao persistir lote de %d itens: %v", len(*lote), err)
	}
	*lote = (*lote)[:0]
}

// Fechar drena o canal e aguarda o último flush antes de retornar —
// usado durante o graceful shutdown para não perder eventos em memória.
func (b *BatchIngestor) Fechar() {
	close(b.canal)
	b.wg.Wait()
}

var ErrBufferCheio = &erroIngestao{"buffer de ingestão cheio, tente novamente"}

type erroIngestao struct{ msg string }

func (e *erroIngestao) Error() string { return e.msg }

💻 Código de Exemplo 02 — Trilha de Auditoria Assinada com HMAC-SHA256

package auditoria

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"time"
)

type EventoAuditoria struct {
	Timestamp  int64  `json:"timestamp"`
	Operacao   string `json:"operacao"`
	Detalhe    string `json:"detalhe"`
	Assinatura string `json:"assinatura"`
}

// AssinarEvento gera um evento de auditoria com HMAC-SHA256, garantindo que
// qualquer alteração posterior do registro no banco seja detectável.
func AssinarEvento(operacao, detalhe string, chaveSecreta []byte) EventoAuditoria {
	ts := time.Now().UTC().Unix()
	mensagem := fmt.Sprintf("%d:%s:%s", ts, operacao, detalhe)

	h := hmac.New(sha256.New, chaveSecreta)
	h.Write([]byte(mensagem))
	assinatura := hex.EncodeToString(h.Sum(nil))

	return EventoAuditoria{Timestamp: ts, Operacao: operacao, Detalhe: detalhe, Assinatura: assinatura}
}

// VerificarIntegridade recalcula o HMAC e compara com hmac.Equal — nunca com
// "==" direto, que é vulnerável a timing attacks por comparar byte a byte
// com retorno antecipado na primeira diferença.
func VerificarIntegridade(evento EventoAuditoria, chaveSecreta []byte) bool {
	mensagem := fmt.Sprintf("%d:%s:%s", evento.Timestamp, evento.Operacao, evento.Detalhe)
	h := hmac.New(sha256.New, chaveSecreta)
	h.Write([]byte(mensagem))
	assinaturaEsperada := hex.EncodeToString(h.Sum(nil))

	return hmac.Equal([]byte(assinaturaEsperada), []byte(evento.Assinatura))
}

💻 Código de Exemplo 03 — main.go: Wiring Completo com Graceful Shutdown

package main

import (
	"context"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"meuservico/domain"
	"meuservico/usecase"
)

type persistidorGorm struct{}

func (persistidorGorm) SalvarLote(pedidos []domain.PedidoAltaVazao) error {
	// db.CreateInBatches(&pedidos, 500) em uma implementação real com GORM
	log.Printf("lote persistido: %d pedidos", len(pedidos))
	return nil
}

func main() {
	ingestor := usecase.NovoIngestor(persistidorGorm{}, 10_000, 500, 500*time.Millisecond)
	ingestor.IniciarProcessadorLote()

	router := gin.New()
	router.Use(gin.Recovery())
	router.GET("/metrics", gin.WrapH(promhttp.Handler()))

	router.POST("/pedidos", func(c *gin.Context) {
		var req struct {
			ClienteID uint    `json:"cliente_id" binding:"required"`
			Valor     float64 `json:"valor" binding:"required,gt=0"`
		}
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"erro": err.Error()})
			return
		}
		if err := ingestor.Ingerir(domain.NovoPedido(req.ClienteID, req.Valor)); err != nil {
			c.JSON(http.StatusServiceUnavailable, gin.H{"erro": err.Error()})
			return
		}
		c.JSON(http.StatusAccepted, gin.H{"status": "aceito"})
	})

	srv := &http.Server{Addr: ":8080", Handler: router}
	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("erro ao iniciar servidor: %v", err)
		}
	}()
	log.Println("servidor de alta vazão escutando em :8080")

	// Graceful shutdown: aguarda SIGINT/SIGTERM do orquestrador (ex: Kubernetes)
	sinal := make(chan os.Signal, 1)
	signal.Notify(sinal, syscall.SIGINT, syscall.SIGTERM)
	<-sinal
	log.Println("sinal de encerramento recebido, drenando requisições em andamento...")

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Printf("shutdown forçado após timeout: %v", err)
	}

	ingestor.Fechar() // drena o buffer de ingestão antes de encerrar o processo
	log.Println("encerramento concluído com sucesso.")
}