2019年11月18日月曜日

go-workers で失敗したジョブをリトライさせる

概要

go-workers ではデフォルトだと失敗したジョブはリトライされません
意図的にリトライさせるにはエンキュー時にリトライをオンにする必要があります
今回はその方法を紹介します 

環境

  • macOS 10.15
  • golang 1.12.9
  • go-workers dbf81d0b75bbe2fd90ef66a07643dd70cb42a88a

事前準備

  • redis-server

失敗するコード

まずはワーカーが失敗するコードを作成します

  • vim main.go
package main

import "github.com/jrallison/go-workers"

func main() {
        workers.Configure(map[string]string{
                "server":   "localhost:6379",
                "process": "1",
        })
    workers.EnqueueWithOptions("default", "SampleWorker", []int{1, 2}, workers.EnqueueOptions{Retry: true})
}
  • vim worker.go
package main

import (
    "fmt"
    "github.com/jrallison/go-workers"
)

func perform(msg *workers.Msg) {
    fmt.Println("perform")
    fmt.Println(msg.Jid())
    a, _ := msg.Args().String()
    fmt.Println(a[0])
}

func main() {
    workers.Configure(map[string]string{
        "server":  "localhost:6379",
        "process": "1",
    })
    workers.Process("default", perform, 1)
    workers.Run()
}

これでそれぞれ実行してみます

  • go run main.go
  • go run worker.go

するとエラーが表示され失敗したジョブをカウントする stat:failed に格納されます

  • redis-cli keys '*'
stat:failed queues stat:failed:2019-11-18
  • redis-cli get 'stat:failed'
1

リトライさせる

エンキューさせる時にリトライオプションを付与します

  • vim main.go
package main

import "github.com/jrallison/go-workers"

func main() {
        workers.Configure(map[string]string{
                "server":   "localhost:6379",
                "process": "1",
        })
    workers.EnqueueWithOptions("default", "SampleWorker", []int{1, 2}, workers.EnqueueOptions{Retry: true})
}

workers.EnqueueWithOptions を使ってエンキューし workers.EnqueueOptions{Retry: true} を指定します
これで実行してみます

  • go run main.go
  • go run worker.go

すると stat:failed はカウントされるものの失敗したジョブの情報が goretry に格納されるようになります

  • redis-cli keys '*'
queues stat:failed:2019-11-18 stat:failed goretry
  • redis-cli zrange 'goretry' 0 -1
{"args":[1,2],"class":"SampleWorker","enqueued_at":1574046394.6627982,"error_message":"runtime error: index out of range","failed_at":"2019-11-18 03:05:57 UTC","jid":"74ffa4ab4e81a809c9bd7002","queue":"default","retried_at":"2019-11-18 03:06:34 UTC","retry":true,"retry_count":1}

しばらくするとリトライされます
リトライの仕組みは Sidekiq とおそらく同じでバックオフを採用しています (30s -> 46s -> 1m16s …)

デフォルトだと最大で 25 回リトライします

回数を指定してリトライさせる

25 回リトライさせない場合はリトライをカウントするインクリメント数を指定します
例えば 2 回リトライさせたい場合には インクリメントする数字を 13 にします
インクリメントする数字はエンキュー時のオプションに RetryCount を付与します

  • vim main.go
package main

import "github.com/jrallison/go-workers"

func main() {
        workers.Configure(map[string]string{
                "server":   "localhost:6379",
                "process": "1",
        })
    workers.EnqueueWithOptions("default", "SampleWorker", []int{1, 2}, workers.EnqueueOptions{Retry: true, RetryCount: 13})
}

今回はテストなので 13 にしています
この数字分リトライカウントがインクリメントされます
インクリメント後に 25 以上の数字になればリトライは終了します

ただ上記の場合次回実行時は 8 時間後くらいになります
さきほど説明した通り Sidekiq はバックオフなので 13 回リトライしたあとの時間分待つことになります

最後に

go-workers でリトライする方法を紹介しました
基本的には Sidekiq のリトライ方式を踏襲しているので最大 25 回でリトライの待ち時間はバックオフになります

デフォルトではリトライは無効になっているので使用する場合にはオプション付きでエンキューしましょう
またリトライ回数を指定したい場合は RectryCount を調整することでリトライ回数を指定しましょう

参考サイト

0 件のコメント:

コメントを投稿