LoginSignup
40
39

More than 5 years have passed since last update.

Goのバッチで統計を取得するAPIを用意しておくと便利

Last updated at Posted at 2015-09-01

golangで以下のようなKillするまでずっと動くバッチがあるとします。

package main

import (
    "fmt"
    "sync"
    "time"
)

// なんかしらの処理
func someprocess() {
    somedata := []string{"a", "b", "c", "d", "e"}

    var wg sync.WaitGroup
    for _, s := range somedata {
        wg.Add(1)
        go func(val string) {
            defer wg.Done()
            fmt.Println(val)
        }(s)
    }
}

func main() {
    // ずっと動き続ける
    for {
        someprocess()
        time.Sleep(3 * time.Second)
    }
}

このとき、この処理の稼働状況を知りたくなるのが人の常なので、以下のようにhttpサーバを立てて、
jsonで統計情報を取得できるようにしておくと便利です。
(統計情報の書き込みでロックが発生しますが、処理量にもよりますがほとんど問題にならないはず。)

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"
    "sync"
    "time"
)

var metrics *Metrics

type Metrics struct {
    sync.RWMutex
    PID          int
    StartedAt    time.Time
    LastWorkedAt time.Time
    LoopCount    int
    DataCount    int
}

func someprocess() {
    somedata := []string{"a", "b", "c", "d", "e"}

    var wg sync.WaitGroup
    for _, s := range somedata {
        wg.Add(1)
        go func(val string) {
            defer wg.Done()
            fmt.Println(val)

            // 詳細な処理の統計を更新
            metrics.Lock()
            defer metrics.Unlock()
            metrics.DataCount++
        }(s)
    }
}

func init() {
    metrics = &Metrics{
        PID:          os.Getpid(),
        StartedAt:    time.Now(),
        LastWorkedAt: time.Now(),
        DataCount:    0,
    }
}

func MetricsHandler(w http.ResponseWriter, r *http.Request) {
    metrics.RLock()
    defer metrics.RUnlock()
    b, err := json.Marshal(metrics)
    if err != nil {
        http.Error(w, http.StatusText(500), 500)
    }

    fmt.Fprintf(w, string(b))
}

func main() {
    go func() {
        for {
            someprocess()

            // 1ループごとの統計を更新
            metrics.Lock()
            metrics.LoopCount++
            metrics.LastWorkedAt = time.Now()
            metrics.Unlock()
            time.Sleep(3 * time.Second)
        }
    }()

    // 実行状況を表示するHTTPサーバを立てる。
    port := 9001
    http.HandleFunc("/metrics", MetricsHandler)
    fmt.Printf("Listening on %d...\n", port)
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}

起動後、http://localhost:9001/metricsにアクセスすると、以下のようなjsonが返ってきます。

{
  "PID": 85568,
  "StartedAt": "2015-08-31T20:41:19.326943122+09:00",
  "LastWorkedAt": "2015-08-31T20:41:43.350825325+09:00",
  "LoopCount": 9,
  "DataCount": 45
}

これを監視するとかしておくとよいのではないでしょうか。

40
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
39