App Engine Modules and Go / Golang

21 Mar
21/03/2014

Update: If you’re primarily interested into separating module code into its own, distinct Go compiled binaries and packages, you might want to follow along the discussion on Google+.

Recently Google deprecated App Engine Backends in favour of Modules.

In my case, I want to use Modules to bundle indefinitely running processes responsible for frequently persisting data from Dedicated Memcache to Datastore. These processes should live outside any request context and just run “forever”.

An important aspect for me is to keep the module code separate from my main application’s code. On App Engine for Python and PHP this is pretty obvious, as one can simply map URIs to scripts. On the contrary, App Engine for Go uses a single binary and all of the URI matching is handled from within the compiled program.

Unfortunately, the Golang Modules documentation is incomplete and not extremely helpful in getting you up and running using Modules. For example, the samples for Module YAML files, do not include the handlers tag – which not only seems to be required in app.yaml but also on the module level.

Disclaimer: While I am not at all sure whether what I describe here is the correct, best or even idiomatic way of doing it, I can confirm it is working. Any comments are appreciated. You might also want to get in touch with me on TwitterApp.net or Google+.

I hope, Google will amend their docs so we all have a chance to find out how exactly Mountain View intends us to use Modules.

Folder structure

My project structure looks something like this:

/ Project root containing the .yaml files
/main The main applications .go files
/config Configuration files
/services Go files for shared services
/etl The Go files for the ETL Module

YAML files

The main app.yaml file is absolutely straight forward:

app.yaml

 

Here is the etl.yaml file:

etl.yaml

A couple of important things to note:

  • I’m using the manual scaling instance type, which according to Google’s docs facilitate the following: “Requests can run indefinitely. A manually-scaled instance can choose to handle /_ah/start and execute a program or script for many hours without returning an HTTP response code.”
  • I have added a handlers section. Google does not illustrate this in their docs, but without a handlers section, I couldn’t get Modules to work at all. Also note that the modules registers for the /_ah/.* URI pattern. If you try to register the Module for any pattern, that gets registered by another Module or the default Module, you will see “panic: http: multiple registrations for / goroutine” errors in your logs.

The code

In my main application, I’m using the Martini web framework to route requests. The code lives in the /main folder and is not particularly important to understanding how to set up Modules.

The ETL Module lives in the /etl folder and does not make use of the Martini framework, as it essentially just needs to handle the start and stop triggers requested by App Engine’s runtime environment:

Again, a few things to note:

  • The Module belongs to the same package as the rest of my code. While the code for the Module is cleanly separated, we still get just one single binary.
  • The Module implements handlers for  /_ah/start and /_ah/stop. Once an instance configured for manual scaling is fired up, App Engine automatically sends an empty GET request to /_ah/start.
  • The rest of the code is straight forward: I’m using runtime.RunInBackground to start a background process which – in this case – will run forever.
  • The first thing I do in the handlers is returning a response. If a Module does not respond with an HTTP 200 to /_ah/start, App Engine, the runtime environment will shut down the Module. (You can use this to signal initialisation or other failures to App Engine, by responding with a 404).

goapp deploy and the development server

goapp is just a thin wrapper around appcfg. To deploy your app along with its modules just type: goapp deploy app.yaml etl.yaml. Though the goapp serve app.yaml etl.yaml command works, too, I couldn’t get the module working on my local development server. If anybody figures it out, let me know!

This is my take on Golang Modules for App Engine. I’m looking forward to getting your feedback and possible hints of how to improve the code and setup.


Tags: ,
2 replies
  1. Glenn Lewis says:

    I posted a reply on your G+ post, but thought it might be useful to others to also respond here.

    A customized dispatch.yaml file will allow you to set up routing. See these pages for more information:
    https://developers.google.com/appengine/docs/go/modules/
    https://developers.google.com/appengine/docs/go/modules/routing

    For example:
    $ find .
    ./static_backend
    ./static_backend/s.go
    ./static_backend/static_backend.yaml
    ./mobile_frontend
    ./mobile_frontend/m.go
    ./mobile_frontend/mobile_frontend.yaml
    ./frontend
    ./frontend/frontend.go
    ./frontend/app.yaml
    ./dispatch.yaml

    $ cat dispatch.yaml
    application: module-go

    dispatch:
    # Default module serves the typical web resources and all static resources.
    – url: “*/favicon.ico”
    module: default

    # Send all mobile traffic to the mobile frontend.
    – url: “*/mobile/*”
    module: mobile-frontend

    # Send all work to the one static backend.
    – url: “*/work/*”
    module: static-backend

    Then, you would use appcfg.py to upload the dispatch.yaml file to App Engine:
    $ appcfg.py –oauth2 update_dispatch .

    For further assistance, it may be easier to post questions on the google-appengine-go mailing list:
    https://groups.google.com/forum/#!forum/google-appengine-go

    Reply
  2. Ivan Hawkes says:

    Thanks guys, that really helps clear things up!

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *

* Copy This Password *

* Type Or Paste Password Here *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© Copyright 2013 by Ralf Rottmann. rottmann.net is a work in progress by Ralf Rottmann. This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
If you would like to make use of any of the content you see here, please contact the author.