uWSGI Go support (1.4 only)

Warning

Starting from 1.9.20, the Go plugin has been superseded by the The GCCGO plugin plugin.

Starting from uWSGI 1.4-dev you can host Go web applications in your uWSGIstack. You can download Go from http://golang.org/ . Currently Linuxi386/x86_64, FreeBSD i386/x86_64 and OSX are supported. For OSX support, youneed Go 1.0.3+ or you will need to apply the patch available athttp://code.google.com/p/go/source/detail?r=62b7ebe62958 Goroutines arecurrently supported only on Linux i386/x86_64.

Building uWSGI with Go support

Go support can be built as an embedded component or plugin. The maindifference with the setup of other languages is this time we will build a uwsgilibrary and not a uwsgi binary. This library will be used by a Go package nameduwsgi.go you can link with your apps. Do not be afraid as in the uWSGIdistribution there is already a build profile to make a completely (monolithic)distribution with Go support embedded. At the end of the build procedure youwill have a libuwsgi.so shared library and a uwsgi.a Go package.

To build uWSGI+go just run (from uWSGI sources directory)

  1. UWSGI_PROFILE=go make

or if Python is not in your system path, or you need to use a specific pythonversion:

  1. /usr/local/bin/python uwsgiconfig.py --build go

(or wherever your custom Python is)

At the end of the build procedure you will have a libuwsgi.so file (copy orlink it to a library directory like /usr/local/lib or /usr/lib and eventuallyrun ldconfig if needed) and a uwsgi.a file in a subdirectory (based on yourarch/os) in plugins/go/pkg.

Important

The last message from the build procedure reports the GOPATH you shoulduse when building uWSGI Go apps (copy/remember/annotate that valuesomewhere).

If you already know how the Go import system works, feel free to copyuwsgi.a in your system-wide GOPATH.

Writing the first Go application

By default the uWSGI Go plugin supports the http.DefaultServeMux handler,so if your app is already based on it, running it in uWSGI should be extremelysimple.

  1. package main
  2.  
  3. import (
  4. "uwsgi"
  5. "net/http"
  6. "fmt"
  7. )
  8.  
  9. func oneHandler(w http.ResponseWriter, r *http.Request) {
  10. fmt.Fprintf(w, "<h1>One</h1>")
  11. }
  12.  
  13.  
  14. func twoHandler(w http.ResponseWriter, r *http.Request) {
  15. fmt.Fprintf(w, "<h2>Two</h2>")
  16. }
  17.  
  18. func main() {
  19. http.HandleFunc("/one/", oneHandler)
  20. http.HandleFunc("/two/", twoHandler)
  21. uwsgi.Run()
  22. }

As you can see, the only differences from a standard net/http-basedapplication are the need to import "uwsgi" need and calling uwsgi.Run()function, which will run the whole uWSGI server. If you want to use yourpersonal request handler instead of http.DefaultServeMux, useuwsgi.Handler(http.Handler) oruwsgi.RequestHandler(func(http.ResponseWriter, *http.Request)) to set it.

  1. func myHandler(w http.ResponseWriter, r *http.Request) {
  2. fmt.Fprintf(w, "<h2>Two</h2>")
  3. }
  4.  
  5. func main() {
  6. uwsgi.RequestHandler(myHandler)
  7. uwsgi.Run()
  8. }

Building your first app

Assuming you saved your app as helloworld.go, just run the following.

  1. GOPATH=/home/foobar/uwsgi/plugins/go go build helloworld.go

change GOPATH to the value you got from the build procedure, or to the dir youhave installed/copied uwsgi.a If all goes well you will end with a ‘helloworld’executable. That executable is a full uWSGI server (yes, really).

  1. ./helloworld --http :8080 --http-modifier1 11

Just point your browser to the port 8080 and check /one/ and /two/ You canstart adding processes and a master:

  1. ./helloworld --http :8080 --http-modifier1 11 --master --processes 8

Note: modifier1 11 is officially assigned to Go.

Going in production

In a production environment you will probably put a webserver/proxy in front ofyour app. Thus your nginx config will look like this:

  1. location / {
  2. include uwsgi_params;
  3. uwsgi_pass 127.0.0.1:3031;
  4. uwsgi_modifier1 11;
  5. }

while your uWSGI config will be something like this…

  1. [uwsgi]
  2. socket = 127.0.0.1:3031
  3. master = true
  4. processes = 4

Finally simply run your app:

  1. ./helloworld config.ini

Goroutines (currently Linux/FreeBSD-only)

Goroutines are very probably the most interesting feature of the Go platform.A uWSGI loop engine for goroutines is automatically embedded in the uWSGIlibrary when you build it with the go plugin. To spawn goroutines in eachuWSGI process just add the goroutines = N option, where N is the number ofgoroutines to spawn.

  1. [uwsgi]
  2. socket = 127.0.0.1:3031
  3. master = true
  4. processes = 4
  5. goroutines = 100

With this config you will spawn 100 goroutines for each uWSGI process, yieldinga grand total of 400 goroutines (!) As far as uWSGI is concerned, goroutinesmap to pthreads, but you will be able to spawn coroutine-based tasks from yourapplication as well.

uWSGI api

It is fairly simple to access the uWSGI API from your Go app. To do so invokethe functions exported by the uwsgi package:

  1. package main
  2.  
  3. import (
  4. "fmt"
  5. "uwsgi"
  6. )
  7.  
  8. func hello2(signum int) {
  9. fmt.Println("I am an rb_timer running on mule", uwsgi.MuleId())
  10. }
  11.  
  12. func hello(signum int) {
  13. fmt.Println("Ciao, 3 seconds elapsed")
  14. }
  15.  
  16. func postinit() {
  17. uwsgi.RegisterSignal(17, "", hello)
  18. uwsgi.AddTimer(17, 3)
  19.  
  20. uwsgi.RegisterSignal(30, "mule1", hello2)
  21. uwsgi.AddRbTimer(30, 5)
  22. }
  23.  
  24. func foofork() {
  25. fmt.Println("fork() has been called")
  26. }
  27.  
  28. func main() {
  29. uwsgi.PostInit(postinit)
  30. uwsgi.PostFork(foofork)
  31. uwsgi.Run()
  32. }

The PostInit() function set the ‘hook’ to be called after the Go initializationis complete. The PostFork() function set the ‘hook’ to be called after eachfork() In postinit hook we register two uwsgi signals, with the second onebeing run in a mule (the mule1) To run the code just build your new app asabove and execute it

  1. [uwsgi]
  2. socket = 127.0.0.1:3031
  3. master = true
  4. processes = 2
  5. goroutines = 20
  6. mules = 2
  7. memory-report = true

This time we have added memory-report, try it to see how memory-cheap Go appscan be.

Running from the Emperor

If you are running in Emperor mode, you can run uWSGI-Go apps by using theprivileged-binary-patch option. Your vassal configuration should besomething like this.

  1. [uwsgi]
  2. socket = 127.0.0.1:3031
  3. master = true
  4. processes = 2
  5. goroutines = 20
  6. mules = 2
  7. memory-report = true
  8. uid = foobar
  9. gid = foobar
  10. privileged-binary-patch = /tmp/bin/helloworld

(Obviously change /tmp/bin/helloworld to wherever your app lives…)

Notes

  • A series of interesting go examples can be found in the t/go directory ofthe uWSGI source distribution.
  • Changing process names is currently not possible without modifying the go core
  • You cannot use uWSGI native threads with Go (just use –goroutines)
  • Only a little part of the uWSGI API has been exposed so far. If you want tohack on it or need more, just edit the uwsgi.go file in theplugins/go/src/uwsgi directory
  • Goroutines require the async mode (if you are customizing your uWSGI libraryremember to always include it)
  • It looks like it is possible to load the Python, Lua and PSGI plugins withoutproblems even in goroutines mode (more tests needed)