🌵

べき等性パターン(#1)

2021/05/16に公開

tl;dr

  • べき等大事だよ
  • 今回は背景と、べき等ではない例を説明するよ

背景

べき等性(Idempotence)とは

なんらかの理由で、本来は一度だけの処理が複数回実行されてしまう場合があります。処理が複数回実行されても大丈夫な場合、べき等(idempotence)と言います。

なお、名著データ志向アプリケーションデザインでは、「複数回実行することができ、その影響が一度だけ実行したときと同じになるような操作」(P.523)と定義されています。

なぜ、べき等性を気にする必要があるか

処理を正確に一度実行することは一般論として難しいです。Apache AirflowやApache Beam(※)などの分散処理システムでは、

  • あるワーカーが処理をする
  • 処理が終わったことを報告する前に、ワーカーが死ぬ
  • 処理が失敗したと判断され、別のワーカーが処理を実行

などの場合があるので、とりわけ難しいです。

そのため、これらのシステムでは、べき等性を気にして実装することが勧められています。例えば、
Beamでは、

In addition, it’s recommended that you make your function object idempotent. Non-idempotent functions are supported by Beam, but require additional thought to ensure correctness when there are external side effects.
(関数をべき等にした方が良いよ。べき等でない関数もサポートされているけど、正しさを外部システム側で確保する方法を考える必要があるよ)

と、プログラミングガイドに記載されています。

※正確には、それを実行するRunner(Cloud DataflowやApache Spark)

なぜ、この記事を書いているか

「べき等にしたほうが良いよ」としても、実際どう実装すれば良いかは、それほど明白ではありません。
分散システムのOSSなどには、べき等を考慮したコードの例があるので、それを整理し、べき等にしたい時の参考にしようと思った次第です。

パターン0:べき等にしない

どんな時に使う

「べき等にしたほうが良いよ」と書いておいた後ですが、べき等な実装を「常に」する必要はありません。
複数回実行されたとしても困る人が誰もいなければ、我々も気にする必要はないでしょう。

例: AirflowのEmailOperator

Airflowには、EmailOperatorという、メールを送るOperatorがあります。
具体的な処理は、email_backendで指定されるコード(※)で実装されるのですが、SMTPによる処理(send_email_smtp)では、

を行っているだけなので、同じメールが複数回送られる可能性はあります
(処理の途中で失敗しリトライや、タスクの再実行(backfillやclear

ドキュメントに記載がないのであくまで想像ですが、べき等にしていないのは、

  • この処理をべき等にするのが難しい
  • EmailOperatorの典型的な使い方は、ETL処理の成功・失敗時の通知なので、二度送られても、メールを読む人がスルーすればすむ話

などの理由ではないでしょうか。

※ 他にSendGridなどの実装が存在

Discussion