2011年5月29日日曜日

Trying Google App Engine SDK for Go (2)

パニクったらどうなるの

moustachioのサンプルを見ると、ハンドル関数uploadを登録するときにerrorHandlerという関数(関数を返す関数)でラップした上で登録している。これはもしuploadのなかでpanicが起きたときに適切なエラーハンドルをするための措置みたい。

errorHandlerの用法

func init() {
        http.HandleFunc("/", errorHandler(upload))
        ...
}

...
 
// errorHandler wraps the argument handler with an error-catcher that
// returns a 500 HTTP error if the request fails (calls check with err non-nil).
func errorHandler(fn http.HandlerFunc) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                defer func() {
                        if err, ok := recover().(os.Error); ok {
                                w.WriteHeader(http.StatusInternalServerError)
                                errorTemplate.Execute(w, err)
                        }
                }()
                fn(w, r)
        }
}

わざわざこういうエラーハンドラが存在する必要が良くわからなかったので、このエラーハンドルを通さず意図的にpanicを起こしたらどうなるかを見てみた。

サンプル

package hello

import (
    "fmt"
    "http"
)

func init() {
    http.HandleFunc("/", root)
}

func root(w http.ResponseWriter, r *http.Request) {
    // test panic here to see what happens
    panic("Testing panic")

    ch := make(chan string, 1)
    go func(){
        ch <- "aaaaa!!"
    }()
    fmt.Fprint(w, "At Root! ", <- ch)
}

実行結果

どうやらデフォルトのエラーハンドラが動いて、ブラウザ上はInternal Server Errorが発生したことが伝わるみたい。ただ、クライアントに対して適切なエラーコードが送られたかどうかは定かでない。

スクリーンショット

dev_appserverのログ

$ dev_appserver.py myapp/
Warning: You are using a Python runtime (2.7) that is more recent than the production runtime environment (2.5). Your application may use features that are not available in the production environment and may not work correctly when deployed to production.
INFO     2011-05-29 02:42:43,751 appengine_rpc.py:159] Server: appengine.google.com
INFO     2011-05-29 02:42:43,754 appcfg.py:440] Checking for updates to the SDK.
INFO     2011-05-29 02:42:44,311 appcfg.py:457] The SDK is up to date.
WARNING  2011-05-29 02:42:44,311 datastore_file_stub.py:657] Could not read datastore data from /tmp/dev_appserver.datastore
INFO     2011-05-29 02:42:44,313 rdbms_sqlite.py:58] Connecting to SQLite database '' with file '/tmp/dev_appserver.rdbms'
INFO     2011-05-29 02:42:44,366 dev_appserver_multiprocess.py:637] Running application xclamm on port 8080: http://localhost:8080
INFO     2011-05-29 02:42:52,748 __init__.py:284] building _go_app
INFO     2011-05-29 02:42:53,503 __init__.py:276] running _go_app
panic: Testing panic

runtime.panic+0xa4 /tmp/appengine/google_appengine/goroot/src/pkg/runtime/proc.c:1060
 runtime.panic(0x811c8e4, 0x9762b550)
hello.root+0x4e hello/panic.go:14
 hello.root(0x976a54a0, 0x9762cf60)
http.HandlerFunc·ServeHTTP+0x35 /tmp/appengine/google_appengine/goroot/src/pkg/http/server.go:533
 http.HandlerFunc·ServeHTTP(0x805b7f0, 0x976a54a0, 0x9762cf60, 0x976bc000, 0x805b7f0, ...)
http.*ServeMux·ServeHTTP+0x194 /tmp/appengine/google_appengine/goroot/src/pkg/http/server.go:728
 http.*ServeMux·ServeHTTP(0x9762b2f0, 0x976a54a0, 0x9762cf60, 0x976bc000, 0x9762cf60, ...)
http.*conn·serve+0x202 /tmp/appengine/google_appengine/goroot/src/pkg/http/server.go:499
 http.*conn·serve(0x9762ce40, 0x0)
runtime.goexit /tmp/appengine/google_appengine/goroot/src/pkg/runtime/proc.c:178
 runtime.goexit()
----- goroutine created by -----
http.*Server·Serve+0x1cf /tmp/appengine/google_appengine/goroot/src/pkg/http/server.go:820
(後略)

まとめ

一応デフォルトのエラーハンドラは存在するみたい。でもやっぱり自分でハンドルしたほうがいいね。

  • Go版のGoogle App Engineには(一応)デフォルトのエラーハンドラがいる
  • クライアントに適切なエラーコードを返してるかは定かでない
  • どっちにしろ見た目がしょぼいから自分でエラーハンドルしたほうがいい

2011年5月17日火曜日

Trying Google App Engine SDK for Go

Google App EngineがGoに対応したとかで、とりあえず試してみることにした。

インストール

何はともあれSDKをダウンロードしてきてパスを通す。

$ cd ~/lib
$ wget http://googleappengine.googlecode.com/files/go_appengine_sdk_linux_386-1.5.0.zip
$ unzip go_appengine_sdk_linux_386-1.5.0.zip
$ export PATH=~/lib/google_appengine/:$PATH

サンプルの作成と実行

サンプルの作成手順は本家ドキュメントに任せるとして、ここでは実際の実行結果を見ていく。

$ dev_appserver.py myapp/
Warning: You are using a Python runtime (2.6) that is more recent than the production runtime environment (2.5). Your application may use features that are not available in the production environment and may not work correctly when deployed to production.
INFO     2011-05-17 14:17:10,225 appengine_rpc.py:159] Server: appengine.google.com
INFO     2011-05-17 14:17:10,229 appcfg.py:440] Checking for updates to the SDK.
INFO     2011-05-17 14:17:10,550 appcfg.py:457] The SDK is up to date.
WARNING  2011-05-17 14:17:10,550 datastore_file_stub.py:657] Could not read datastore data from /tmp/dev_appserver.datastore
INFO     2011-05-17 14:17:10,552 rdbms_sqlite.py:58] Connecting to SQLite database '' with file '/tmp/dev_appserver.rdbms'
INFO     2011-05-17 14:17:10,598 dev_appserver_multiprocess.py:637] Running application helloworld on port 8080: http://localhost:8080

これでGoogle App Engineのサーバーがローカルで起動したので、あとはブラウザからhttp://localhost:8080/にアクセスすると、"Hello, World!"と記載されただけのページが表示される。それに併せて、dev_appserver側では以下のログが出てくる。そのログを見ると、実行時にGoのソースをコンパイルして即実行してるのがわかる。

INFO     2011-05-17 14:17:36,341 __init__.py:284] building _go_app
INFO     2011-05-17 14:17:37,011 __init__.py:276] running _go_app
INFO     2011-05-17 14:17:37,080 dev_appserver.py:4200] "GET / HTTP/1.1" 200 -
INFO     2011-05-17 14:17:37,139 dev_appserver.py:4200] "GET /favicon.ico HTTP/1.1" 200 -
INFO     2011-05-17 14:17:40,245 dev_appserver.py:4200] "GET /favicon.ico HTTP/1.1" 200 -