Skip to content

Instantly share code, notes, and snippets.

@ORBAT
Last active May 30, 2023 00:25
Show Gist options
  • Save ORBAT/e83ab05e92885e851d3d3e48c81d18f9 to your computer and use it in GitHub Desktop.
Save ORBAT/e83ab05e92885e851d3d3e48c81d18f9 to your computer and use it in GitHub Desktop.
An example of a Go HTTP server that serves an incrementing counter value
// run this with
// go run counter_server.go
// And then in a new terminal window run
// curl http://localhost:43210
package main
import (
"fmt"
"net/http"
"sync/atomic"
)
// Counter is a HTTP handler that atomically increments a counter on each call to ServeHTTP
type Counter uint64
// ServeHTTP atomically increments a counter, and writes the new value to rw. It implements http.Handler
// (https://godoc.org/net/http#Handler)
func (c *Counter) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// be explicit about ignoring error returned by Close()
_ = req.Body.Close()
rw.WriteHeader(http.StatusOK)
// Go HTTP servers always use multiple goroutines to serve requests, making them automatically
// parallel. This means that we can't write to shared memory in ServeHTTP without somehow
// synchronizing access. Some of the options are channels, mutexes (https://godoc.org/sync#Mutex) or
// doing our data access atomically (https://godoc.org/sync/atomic)
//
// ServeHTTP uses atomic.AddUint64, which atomically adds a number to an uint64. However, just
// writing
// atomic.AddUint64(c)
// would not compile: AddUint64 expects a *uint64 as a paramter, and the type *Counter is not
// assignable to *uint64. For pointer types to be assignable their base type has to be identical,
// and the base types Counter and uint64 aren't.
//
// *Counter can be however _converted_ to a *uint64, because their pointer base types have an
// identical underlying type, uint64
newCounterValue := atomic.AddUint64((*uint64)(c), 1)
result := fmt.Sprintf("%d", newCounterValue)
// Write wants bytes but we have a string, conversion to the rescue.
_, _ = rw.Write([]byte(result))
}
func main() {
handler := Counter(0)
_ = http.ListenAndServe(":43210", &handler)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment