Help us understand the problem. What is going on with this article?

Goji のアプリケーションサーバーを Circus で管理する

More than 3 years have passed since last update.

Goji には graceful shutdown は標準で用意されているのですが、 graceful restart がありません。
調べていたところ Circus というものを見つけたので、以下の記事を参考にやってみました。

Go で書いたサーバーを管理するには circus が便利

Goji でアプリケーションサーバーを書く

まず、 Goji でシンプルなアプリケーションサーバーを書きます。

package main

import (
    "fmt"
    "net/http"

    "github.com/zenazn/goji"
    "github.com/zenazn/goji/web"
)

func helloWorld(c web.C, w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, world!")
}

func main() {
    goji.Get("/", helloWorld)
    goji.Serve()
}

Goji はデフォルトだと 8000 を使うので HTTPie だと以下のようにリクエストを送れます。
(curl など他の HTTP クライアントでも構いません)

$ http GET :8000
HTTP/1.1 200 OK
Content-Length: 13
Content-Type: text/plain; charset=utf-8
Date: Mon, 14 Jul 2015 09:04:21 GMT

Hello, world!

Hello, world! が返ってきました。

Circus 化する

Circus で管理するためにはコードに手を加える必要があります。 Socket の listen は Circus に任せて、アプリケーションは Circus から受け取ったファイルディスクリプタ (FD) を使うからです。

修正後の main は以下のようになります。

func main() {
    goji.Get("/", hello)

    fd := flag.Uint("fd", 0, "File descriptor to listen and serve.")
    flag.Parse()

    if *fd != 0 {
        listener, err := net.FileListener(os.NewFile(uintptr(*fd), ""))
        if err != nil {
            panic(err)
        }
        goji.ServeListener(listener)
    } else {
        goji.Serve()
    }
}

fd フラグで Circus から FD を受け取ります。 Listener を作成したら ServeListener() に渡して listen を開始します。
fd を受け取らなかった場合は Serve() でデフォルト Listener を使用します。 (ポート 8000)

Circus でサーバーを管理する

Circus の設定ファイルを書きます。

[circus]
statsd = 1

[watcher:webapp]
cmd = goji-with-circus --fd $(circus.sockets.web)
stop_signal = SIGINT
numprocesses = 1
use_sockets = True
copy_env = True

[socket:web]
host = 0.0.0.0
port = 8000

cmd が実行されるコマンドです。fd フラグに渡している circus.sockets.web が下の方で定義している socket:web になります。注意点として、 stop_signal に SIGINT を設定しないと Goji は graceful shutdown しません。デフォルトでは SIGTERM が使われるためです。
では実行してみましょう。

$ circusd circus.ini 
2015-07-14 09:13:01 circus[3617] [INFO] Starting master on pid 3617
2015-07-14 09:13:01 circus[3617] [INFO] sockets started
2015-07-14 09:13:01 circus[3617] [INFO] Arbiter now waiting for commands
2015-07-14 09:13:01 circus[3617] [INFO] webapp started
2015/07/14 09:13:01.716297 Starting Goji on 0.0.0.0:8000
2015-07-14 09:13:01 circus[3617] [INFO] circusd-stats started
2015-07-14 09:13:01 circus[3621] [INFO] Starting the stats streamer

これで Circus を使う前と同じようにリクエストを送ることができます。

$ http GET :8000
HTTP/1.1 200 OK
Content-Length: 13
Content-Type: text/plain; charset=utf-8
Date: Tue, 14 Jul 2015 09:14:18 GMT

Hello, world! 

Circus をモニターする

Circus には 2 つのコマンドラインツールが用意されています。そのひとつが circus-top です。

$ circus-top

Circus Top
------------------------------------------------------------------------------------
circus
   PID                      CPU (%)             MEMORY (%)          AGE (s)
  4245 (circusd-stats)       2.60                0.10                77.16
  3617 (circusd)             0.00                0.10                954.12
                             1.30 (avg)          0.20 (sum)          954.12 (older)

sockets
   ADDRESS                  HITS
  0.0.0.0:8000                 0
                               0 (sum)

webapp
   PID                      CPU (%)             MEMORY (%)          AGE (s)
  4244                       0.00                0.00                77.15
                             0.00 (avg)          0.00 (sum)          77.15 (older)

------------------------------------------------------------------------------------

名前のとおり top の Circus 版という位置付けです。プロセスの CPU 使用率などを見ることができます。

Circus を操作する

もうひとつは circusctl です。こちらは Circus に対して様々な操作を行うことができます。

  • watcher の一覧

    $ circusctl list
    circusd-stats,webapp
    
  • watcher に属するプロセスの一覧

    $ circusctl list webapp
    4244
    
  • watcher に属するプロセスの増減

    $ circusctl incr webapp
    ok
    $ circusctl list webapp
    4244,4735
    $ circusctl decr webapp
    ok
    $ circusctl list webapp
    4735
    
  • お待ちかねの graceful restart

    $ circusctl reload
    ok
    

また、 circusctl には REPL も用意されています。

$ circusctl
circusctl 0.12.0
circusd-stats: active
webapp: active
(circusctl) list
circusd-stats,webapp
(circusctl) reload
ok

参考

今回のコードは GitHub にあります。

tchssk/goji-with-circus

tchssk
A web developer who loves Ginger Ale !!
https://tchssk.github.io
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした