Rafael Matsumoto

Rafael Matsumoto

Digital garden

01 Fev 2020

Hot Reloading Go

Reading Time: 1 minute

The example used in this post is based on section 1.7 of the book ‘The Go Programming Language’

While reading the mentioned chapter, I noticed how easy it is to start a web server with the Go language, which gave me the idea to implement a hot-reloader from scratch, a tool very common in web frameworks that significantly aids programming productivity.

Below is a step-by-step guide of how I implemented it.

Code: https://github.com/rafaelmatsumoto/hotreloading-go

Prerequisites:

  • Docker
  • Docker Compose
  • Go

Guide

First step, create a basic script to run the application:

// ./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)
}

To run the application, execute the command:

go run main.go &

After that, when making a GET request, the following response is obtained:

http localhost:8000
HTTP/1.1 200 OK
Content-Length: 15
Content-Type: #00AFAF">text/plain; charset=utf-8
Date: Sat, 01 Feb 2020 16:55:20 GMT

URL.Path = "/"

Implementing hot reloading functionality

We need to create a Dockerfile with the following configuration:

# ./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"]

The reflex library allows adding a listener to execute commands whenever certain file types are changed. The configuration used was:

./reflex.conf

-r '(\.go$|go\.mod)' -s go run main.go &

This configuration determines that if a file with the .go extension or named go.mod is changed, the server is automatically restarted.

After this step, we create a docker-compose.yml file to assist with Docker usage:

# ./docker-compose.yml
version: "2.4"
services:
  app:
    build: .
    volumes:
      - .:/app
    working_dir: /app
    ports:
      - 8000:8000

And we modify the main script for the server to accept external requests:

// ./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)
}

Then we run the command

docker-compose up -d
and that’s it, every new change will be automatically implemented.

Example in practice:

← Back to homepage