0Pricing
Go Academy · レッスン

ジョブのグレースフルシャットダウン

ジョブを適切に停止します

「ジョブのグレースフルシャットダウン」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。

ジョブを適切に停止する

ジョブの実行中にスケジューラーを停止すると、データが破損したり、処理が途中で終わったりする可能性があります。グレースフルシャットダウンとは、新しい実行の受け付けを停止し、実行中のジョブを期限までに完了させてから終了することです。

シグナルを監視する

SIGINT(Ctrl+C)やSIGTERM(オーケストレーターからの停止通知)などのOSシグナルを捕捉すると、意図したタイミングでシャットダウンできます。

sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
fmt.Println("shutting down")

signal.NotifyContext

Go 1.16以降では、シグナルを受け取ったときにコンテキストをキャンセルする便利なヘルパーが用意されています。

ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
<-ctx.Done()

スケジューラーを停止する

robfig/cronでは、c.Stop()が、実行中のすべてのジョブが完了すると終了するコンテキストを返します。そのコンテキストを待機して、ジョブの完了を待ちます。

ctx := c.Stop()        // stops scheduling, returns ctx
<-ctx.Done()            // wait for running jobs
fmt.Println("all jobs finished")

ジョブにキャンセルを伝播する

各ジョブにコンテキストを渡すと、シャットダウンが始まったときに時間のかかる処理をすぐに中断できます。

func job(ctx context.Context) {
    select {
    case <-time.After(time.Hour):
    case <-ctx.Done():
        return // bail out early
    }
}

待機時間に上限を設ける

停止しないジョブを永遠に待ってはいけません。タイムアウト付きのコンテキストを使うと、ジョブが停止しなくてもシャットダウンを完了できます。

shutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

独自のスケジューラーでWaitGroupを使う

ゴルーチンを使って独自のスケジューラーを作る場合は、sync.WaitGroupでゴルーチンを追跡し、シャットダウン時にWait()を呼び出します。

var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); doWork() }()
// shutdown:
wg.Wait()

新しい処理を開始しない

シャットダウンが始まったら、Tickerやcronは新しい処理を開始してはいけません。完了チャネルを閉じるかコンテキストをキャンセルすると、ループがシグナルを検知して新しい実行のスケジュールを停止します。

冪等性が役立つ

ジョブを安全に再実行できるように設計してください。ジョブが途中で停止し、再起動後に再試行された場合でも、冪等なロジックなら重複した影響(メールの二重送信や二重請求)を避けられます。

完全なパターン

ここまでの内容を組み合わせると、シグナルで通知するコンテキスト、完了を待つコンテキストを返すcronのStop、そして上限付きタイムアウトになります。これは、スケジュールされたサービスで使う標準的なグレースフルシャットダウンの基本形です。

実行可能: コンテキストで適切に停止する

この自己完結型のプログラムは、定期的なワーカーを実行し、コンテキストのキャンセルによって適切に停止します。実行中のティックが完了するまで待機します。

package main

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

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        t := time.NewTicker(5 * time.Millisecond)
        defer t.Stop()
        for {
            select {
            case <-t.C:
                fmt.Println("working")
            case <-ctx.Done():
                fmt.Println("stopping cleanly")
                return
            }
        }
    }()
    time.Sleep(17 * time.Millisecond)
    cancel()   // signal shutdown
    wg.Wait()  // wait for worker to finish
    fmt.Println("shutdown complete")
}

理解度チェック

ジョブのグレースフルシャットダウンについての理解度を確認しましょう。

まとめ

ジョブのグレースフルシャットダウンについて学びました:

  • SIGINTやSIGTERMを捕捉します。できればsignal.NotifyContextを使います
  • cron.Stop()は、実行中のジョブが完了するまで待機するコンテキストを返します
  • コンテキストをジョブに伝播し、タイムアウトで待機時間に上限を設けます
  • 再試行しても安全になるよう、ジョブを冪等にします

よくある質問

「ジョブのグレースフルシャットダウン」レッスンは無料ですか?

はい。「ジョブのグレースフルシャットダウン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。

「ジョブのグレースフルシャットダウン」で何を学びますか?

ジョブを適切に停止します ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Go Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「ジョブのグレースフルシャットダウン」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このGo Academyレッスンでコードを書いて実行できますか?

はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 時間ベースのスケジューリング
  2. robfig/cronライブラリ
  3. 間隔処理用のTicker
  4. ジョブのグレースフルシャットダウン
← Go Academyに戻る