Como fazer graceful shutdown correto em um server HTTP

Embora esse tema não seja abordado em exemplos simples de APIs, ele é muito importante. Encerrar um servidor HTTP de forma abrupta, acaba por fechar todas as conexões que ele tem abertas da mesma forma. Em outras palavras, não tratar desligamentos via SIGINT ou SIGTERM de uma API, pode acabar gerando grandes problemas.

Para evitar tais problemas, vou mostrar nesse post como tratar tais sinais e fazer um graceful shutdown do seu servidor HTTP.

Servidor HTTP

Para começar, vamos escrever uma rota que retornará um “hello world”. Vou utilizar o package go-chi para definir a rota não por ser necessário, mas para facilitar o entendimento em aplicações do mundo real.

r := chi.NewRouter()

r.Get("/", func(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello World"))
})
Leia mais »
photo of gray faucet

Como resolver memory leaks em maps

Uma das formas mais comuns de se fazer cache em aplicações Go é utilizando um map. Se você já fez isso, deve ter notado um aumento gradual no consumo de memória, e que normalmente após um restart da máquina ou pod volta ao “normal”.

Isso acontece devido a forma como o map funciona. Por isso, antes de ver o que podemos fazer para resolver esse tipo de problema, vamos entender melhor o map.

Para exemplificar o problema, vamos considerar uma variável do tipo map[int][128]byte, que será “carregada” com 1 milhão de elementos e que na sequência serão removidas.

package main

import (
	"fmt"
	"runtime"
)

func main() {
	n := 1_000_000
	m := make(map[int][128]byte)
	printAlloc()

	for i := 0; i < n; i++ {
		m[i] = [128]byte{}
	}
	printAlloc()

	for i := 0; i < n; i++ {
		delete(m, i)
	}

	runtime.GC()
	printAlloc()
	runtime.KeepAlive(m)
}

func printAlloc() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	fmt.Printf("%d KB\\n", m.Alloc/1024)
}
Leia mais »