データ品質の可視化などに役に立つelementaryだが、稀に以下のようなエラーが発生することがある。このエントリではこのエラーに対する対応方法について考える。
00:03:24 on-run-end failed, error: Query error: Transaction is aborted due to concurrent update against table my-project:my_dataset_elementary.dbt_tests. Transaction ID: xxxx at [6:13]
前提: elementaryの成果物
elementaryはdbt_models
/ dbt_tests
/ dbt_run_results
/ dbt_source_freshness_results
など様々な便利な成果物を出力してくれるが、その成果物は大きく分けると2種類に分けられる。
- A: 現在の設定値
- 現在の設定値であり、履歴を持たない。要するにyamlファイルの内容をSQLで叩きやすいように整形したもの、と思っておけばよい
dbt_models
やdbt_tests
が該当する- 最新の状態のみを持つので、基本的に洗い替えになる
- B: 実行の履歴
dbt_run_results
やdbt_source_freshness_results
が該当する- 実行の履歴なので、yamlには残らない。dbt Cloudを使っているのであればjobの実行履歴に相当するものだし、dbt-coreを使っているのであればログファイルに相当するものでもある
- 基本的にappendしていくもの
エラーの原因
エラーの原因になっているのは主にこの辺のupload_artifacts_func
に関わるところである。引数でshould_commit=true
が指定されており、この場合はトランザクションを掴みにいく挙動になる。そのため、複数のdbtのジョブが走る場合にelementaryが主に動くon-run-end
が被ってしまうと、先にトランザクションを掴めたジョブは成功し、他のジョブは成功(あるいはretryで成功)という挙動になる。
成果物のアップロードをする際、トランザクションを掴みにいく対象としてはdbt_models
/ dbt_tests
/ dbt_sources
/ dbt_snapshots
/ dbt_metrics
/ dbt_exposures
/ dbt_seeds
になっており、上述した「A: 現在の設定値」に関するものが今回のエラーを発生し得る形となる。
エラーの解消方法
dbtを使う上でelementaryは非常に便利なので、今回のエラーが出るからといって利用を諦めるのはもったいない。回避策として以下のようなものが考えられる。
- 同時に実行され得るdbtのjobに関しては
disable_dbt_artifacts_autoupload
設定し、トランザクションでこけ得る対象の除外する- https://docs.elementary-data.com/dbt/on-run-end_hooks#disable-metadata-models-updates
- 「B: 実行の履歴」に関する成果物に関しては引き続きアップロードされる
- 「A: 現在の設定値」に関する成果物をアップロードするため、同時に実行されることがない時間帯にjobの設定をしておく
- トランザクションの掴み合いが起きなくなるため、エラーは発生しない
- ほぼ無意味な
dbt_run_results
が挿入される形になるが、気になるのであればそれらのみ無効化することができる
- jobによって設定値を変えたい場合、dbtのコマンドライン引数から設定することができるので、それを活用しましょう