Last active
May 30, 2023 00:25
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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