Hot Reloading Go
Reading Time: 2 minutos
O exemplo utilizado nesse post foi baseado na seção 1.7 do livro ‘The Go Programming Language’
Ao realizar a leitura do capítulo citado, notei a facilidade de se iniciar um web server com a linguagem Go, tive a ideia de implementar um hot-reloader do zero, ferramenta muito comum em frameworks para a web e que auxilia consideravelmente na produtividade ao programar.
A seguir há um passo-a-passo de como realizei a implementação.
Código: https://github.com/rafaelmatsumoto/hotreloading-go
Pré-requisitos:
- Docker
- Docker Compose
- Go
Guia
Primeiro passo, criar um script básico para rodar a aplicação:
// ./main.go
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
log.Print("Server loaded on port 8000")
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}
Para rodar a aplicação é preciso executar o comando:
go run main.go &
Após isso, ao realizar uma requisição GET a seguinte resposta é obtida:
http localhost:8000 HTTP/1.1 200 OK Content-Length: 15 Content-Type: text/plain; charset=utf-8 Date: Sat, 01 Feb 2020 16:55:20 GMT URL.Path = "/"
Implementando a funcionalidade de hot reloading
É necessário criar um Dockerfile com a seguinte configuração:
# ./Dockerfile
FROM golang:1.13-alpine as base
RUN apk add git
EXPOSE 8000
FROM base as dev
RUN go get github.com/cespare/reflex
COPY reflex.conf /
ENTRYPOINT ["reflex", "-c", "/reflex.conf"]
A biblioteca reflex permite adicionar um listener para executar comandos sempre que algum tipo de arquivo for alterado, a configuração utilizada foi:
./reflex.conf
-r '(\.go$|go\.mod)' -s go run main.go &
Essa configuração determina que, se um arquivo com a extensão .go ou nomeado go.mod for alterado, o servidor é reinicializado automaticamente.
Após essa etapa, criamos um arquivo docker-compose.yml para auxiliar no uso do Docker:
# ./docker-compose.yml
version: "2.4"
services:
app:
build: .
volumes:
- .:/app
working_dir: /app
ports:
- 8000:8000
E alteramos o script principal para o servidor aceitar requisições externas:
// ./main.go
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
log.Print("Server loaded on port 8000")
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe("0.0.0.0:8000", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}
Então rodamos o comando
docker-compose up -de é isto, toda nova alteração será automaticamente implementada.
Exemplo na prática: