k8s.io/apimachinery/pkg/util/wait の使い道
wait が便利なので使いましょう!
Kubernetes に関連する開発を行っていると Reconcile で実行される処理を待つ必要があるケースがよくあります。
その際に wait
を使います。
Overview にも以下のように記載されています、Condition の変更を polling / listening するためのパッケージです。
Package wait provides tools for polling or listening for changes to a condition.
基本的に wait は backoff を行うための関数と polling 行うための関数に分かれています。
Polling
Polling は簡単にいうと一定間隔で何かの状態を確認し続けることです。
condition が true になるまで待ち続ける無限ループみたいなものです。
実際の例だと Pod が Running になるまで待つみたいなことになります。
for {
if condition {
break // finish polling
}
time.Sleep(5 * time.Second) // wait 5 sec and retry
}
PollUntilContextCancel
func PollUntilContextCancel(ctx context.Context, interval time.Duration, immediate bool, condition ConditionWithContextFunc) error
名前の通り渡された Context が cancel されるまで、もしくは condition の関数が true を返すまで待ち続ける関数です。
interval は実行間隔、immediate は最初の interval を待つかどうかを設定できます。
また immediate が true の場合は condition は最低でも一度は実行されます。
Pod が削除されるまで待つようなケースでは普通に書くと select で ctx.Done をハンドリングするコードを書く必要があると思います。
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
for {
select {
case <-ctx.Done():
err := ctx.Err()
if err != nil {
fmt.Printf("Polling failed: %v\n", err)
}
return
default:
pod, err := k8sClient.Get(ctx, client.ObjectKey{ Name:podName, Namespace:namespace })
if apierrors.IsNotFound(err) {
fmt.Println("Pod has been deleted")
return
}
if err != nil {
fmt.Printf("Polling failed: %v\n", err)
return
}
time.Sleep(5 * time.Second)
}
}
PollUntilContextCancel
を使用するとこんな感じで書けます。
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_ := wait.PollUntilContextCancel(ctx, 5*time.Second, func(ctx context.Context) (bool, error) {
_, err := k8sClient.Get(ctx, client.ObjectKey{ Name:podName, Namespace:namespace })
if apierrors.IsNotFound(err) {
fmt.Println("Pod has been deleted")
return true, nil
}
if err != nil {
fmt.Printf("Polling failed: %v\n", err)
return false, err
}
return false, nil
})
PollUntilContextTimeout
func PollUntilContextTimeout(ctx context.Context, interval, timeout time.Duration, immediate bool, condition ConditionWithContextFunc) error
似たような関数で Timeout をハンドルするものもありますが、これは context.WithTimeout を使っていない人のためのもので以下のコードと等価なので基本的には PollUntilContextCancel
を使用するのが良いと思います。
deadlineCtx, deadlineCancel := context.WithTimeout(ctx, timeout)
err := PollUntilContextCancel(deadlineCtx, interval, immediate, condition)
まとめ
wait を使うことで Polling の処理を簡潔に書くことができます、ぜひ使ってみてください。
とりあえず気力で Polling の部分だけ書きました、Backoff や Until も後ほど追記します。
Discussion