タスクグラフでタスクの依存関係を管理する

タスクグラフを使えば、一連のタスクを自動的に実行することができます。タスクグラフ、または有向非巡回グラフ(DAG)は、ルートタスクと子タスクで構成され、依存関係によって編成された一連のタスクです。単一方向のタスクグラフフロー、つまりシリーズの後半のタスクは、前のタスクの実行を促すことができません。各タスクは他の複数のタスクに依存することができ、それらがすべて完了するまで実行されません。各タスクは、それに依存する複数の子タスクを持つこともできます。

タスクグラフのタスクは、親タスクの戻り値を使用して、 SQL 関数本体でロジックベースの操作を実行することもできます。

タスクグラフの作成

タスクグラフを作成するには、タスクを作成または変更するときに親タスクを指定します。グラフのルートタスクは、親タスクを持たないタスクです。ルートタスクには、タスクグラフの実行を開始するスケジュールが定義されている必要があります。各子タスクは、タスクグラフ内のタスクをリンクするために、少なくとも1つの定義された親タスクを持つ必要があります。

子タスクを追加するには、 CREATE TASK ... AFTER または ALTER TASK ... ADD AFTER コマンドを使用します。PythonでSnowflakeタスクとタスクグラフを管理することもできます。詳細については、 PythonによるSnowflakeタスクとタスクグラフの管理 をご参照ください。

タスクグラフの考察
  • タスクグラフは、最大1000タスクに制限されます。

  • 単一のタスクには、最大100個の親タスクと100個の子タスクを含めることができます。

  • タスクグラフを実行するコンピューティングには、タスクの同時実行を処理できるサイズが必要です。詳細については、 コンピューティングリソース をご参照ください。

次の例では、ルートタスクはタスクBとCに同時に実行するように促します。タスクDは、タスクBとCの両方が実行を完了したときに実行されます。

左側にルートタスクとラベル付けされたタスクAがあり、真ん中のタスクBとCの両方を指している菱形のタスクグラフ。タスクBとCは右のタスクDを指しています。

次の例は、タスクグラフを使用して、ファクトデータを集計する前に販売データベースのディメンションテーブルを更新する方法を示しています。

中央にタスクがある菱形のタスクグラフ。左側のルートタスクは、顧客テーブルの更新、商品テーブルの更新、データと時間テーブルの更新タスクを指しています。これら3つのタスクは、右側の「売上集計テーブル」タスクを指します。

この例は、タスクグラフ内の終了タスクが外部関数を呼び出してリモートメッセージングサービスを促し、以前のすべてのタスクが完了まで正常に実行されたという通知を送信することを示しています。

省略記号を使って中間タスクをスキップしたタスクグラフ。左側のルートタスクは、右側の最終的な「外部関数経由で通知を送信」タスクを指す省略記号を指しています。

タスクグラフの所有権の管理

タスクグラフのすべてのタスクには、同じタスク所有者が必要で、同一のデータベースとスキーマに保存されている必要があります。

タスクグラフの全タスクの所有権は、以下のいずれかの操作で移譲できます。

  • DROP ROLE を使用して、タスクグラフのすべてのタスクの所有者を削除します。Snowflake は、DROPROLEコマンドを実行するロールに所有権を移します。

  • スキーマ内のすべてのタスクに対して GRANT OWNERSHIP を使用して、タスクグラフ内のすべてのタスクの所有権を転送します。

これらの方法でタスクグラフ内のタスクの所有権を移譲しても、タスクグラフ内のタ スクは互いの関係を保持したままです。

1つのタスクの所有権を譲渡すると、そのタスクと親タスクおよび子タスクの間の依存関係がなくなります。詳細については、 親タスクと子タスクのリンク解除 (このトピック内)をご参照ください。

注釈

レプリケーションを実行するロールとは別のロールがグラフを所有している場合、データベースのレプリケーションはタスクグラフでは機能しません。

タスクグラフでタスクを実行する

タスクグラフの実行は、定義されたルートタスクの実行によって開始されます。先行タスクが完了するにつれて、ルートタスクが正常に実行されると、タスクグラフ内にある子タスクのカスケード実行がトリガーされます。ルートタスクは以下の方法で実行できます。

  • タスクのスケジュール - 一般的にタスクグラフは、CRONまたはインターバルベースのスケジュールで実行されます。

  • ALTER TASK - ALTER TASK [ IF EXISTS ] < 名前 > RESUME を使って、既存のスケジュールに基づいてタスクグラフを実行することができます。すべてのタスクは最初に作成されたときに再開されなければなりません。

  • EXECUTE TASK - EXECUTE TASK <名前> を使って、タスクグラフの1回限りの実行を作成することができます。

タスクグラフでタスクを手動実行する

EXECUTE TASK コマンドは、タスク用に定義されたスケジュールとは無関係に、タスクの単一実行を手動でトリガーします。先行タスクが完了するにつれて、ルートタスクが正常に実行されると、ルートタスクが定義されたスケジュールで実行されたかのように、タスクグラフ内にある子タスクのカスケード実行がトリガーされます。

また、 EXECUTE TASK <名前> RETRY LAST を使って、タスクグラフの子タスクを再実行することもできます。 RETRY LAST は、最後に失敗したタスクからタスクグラフを実行しようとします。タスクが成功した場合、すべての子タスクは、先行タスクが完了するにつれて実行され続けます。

このSQLコマンドは、運用環境でSQLコードを実行できるようにする前に、新規または変更されたスタンドアロンタスクとタスクグラフをテストするのに役立ちます。

タスクグラフの重複実行

デフォルトでは、Snowflakeは特定のタスクグラフの1つのインスタンスのみが一度に実行できるようにします。ルートタスクの次の実行は、タスクグラフ内のすべてのタスクの実行が終了した後にのみスケジュールされます。これは、タスクグラフ内のすべてのタスクを実行するために必要な累積時間がルートタスクの定義で設定された、明示的にスケジュールされた時間を超える場合、タスクグラフの少なくとも1つの実行がスキップされることを意味します。動作は、ルートタスクのALLOW_OVERLAPPING_EXECUTIONパラメータによって制御されます。デフォルト値はFALSEです。パラメーター値を TRUE に設定すると、タスクグラフの重複実行が許可されます。

さらに、子タスクは、子タスクの すべての 先行タスクが自身の実行を正常に完了した後にのみ実行を開始します。時間のかかるSQL操作を実行するタスクは、タスクを先行タスクとして識別する子タスクの開始を遅らせます。

次の例では、タスクグラフの実行は、前の実行がまだ完了していないときに開始するようにスケジュールされています。重複期間、つまり並行性は赤色で示されます。この図は、各タスクがユーザー管理のウェアハウスで実行される前にキューに入れられた期間も示しています。サーバーレスコンピューティングリソースを使用する場合、キュー期間がないことに注意してください。

タスクグラフの重複実行

タスクグラフの重複実行によって実行される読み取り/書き込み SQL 操作が誤ったデータまたは重複するデータを生成しない場合、重複する実行は許容される(または望ましい)場合があります。ただし、他のタスクグラフの場合、タスク所有者(つまり、タスクグラフ内のすべてのタスクに対して OWNERSHIP 権限を持つロール)は、ルートタスクに適切なスケジュールを設定して、適切なウェアハウス(または、サーバーレスコンピューティングリソース)サイズを選択し、ルートタスクの次回の実行予定前に、タスクグラフのインスタンスが完了するようにする必要があります。

ルートタスクで定義されたスケジュールに合わせてタスクグラフを適切に調整するには、次を実行します。

  1. 可能であれば、ルートタスクの実行間のスケジューリング時間を増やします。

  2. コンピューティングの負荷が大きいタスクは、サーバーレスコンピューティングリソースを使用するように変更することを検討します。タスクがユーザー管理のコンピューティングリソースに依存している場合は、タスクグラフで大規模または複雑な SQL ステートメントやストアドプロシージャを実行するためのウェアハウスサイズを拡大することを検討します。

  3. 各タスクによって実行されるSQLステートメントまたはストアドプロシージャを分析します。並列処理を活用するようにコードを書き直すことができるかどうかを判断します。

上記の解決策のいずれも役に立たない場合は、ルートタスクで ALLOW_OVERLAPPING_EXECUTION = TRUE を設定して、タスクグラフの同時実行を許可する必要があるかどうかを検討してください。タスクの作成時に(CREATE TASK を使用)、または後で(ALTER TASK を使用、または Snowsight で)、このパラメーターを定義できます。

タスクグラフでのタスクの中断と再開

タスクグラフのタスクを中断または再開するには、 ALTER TASK ... RESUME | SUSPEND or the | sf-web-interface|を使います。

ルートタスクの中断

ルートタスクが中断されると、将来のスケジュールされたルートタスクの実行はすべてキャンセルされます。ただし、現在実行中のタスクがある場合、これらのタスクと子孫タスクは引き続き実行されます。

子タスクの再開と中断

子タスクを再開または中断するには、ルートタスクを中断する必要があります。中断された子タスクを再開しても、ルートタスクを再開する必要はありません。

タスクの再帰的再開

タスクグラフ内のすべてのタスクを再帰的に再開するには、 SYSTEM$TASK_DEPENDENTS_ENABLE 関数をクエリします。

中断された子タスクでのタスクグラフの実行

タスクグラフが1つ以上の中断された子タスクで実行される場合、実行はそれらのタスクを無視します。複数の先行タスクを持つ子タスクは、 少なくとも1つ の先行タスクが再開状態にある限り実行され、再開されたすべての先行タスクは正常に完了します。

タスクグラフのバージョン管理

タスクグラフのルートタスクが再開または手動で実行されると、Snowflakeは、タスクグラフ内のすべてのタスクのすべてのプロパティを含む、タスクグラフ全体のバージョンを設定します。タスクが中断および変更された後、ルートタスクが再開されるか、手動で実行されると、Snowflakeが新しいバージョンが設定します。

タスクグラフ内にある任意のタスクを変更または再作成するには、最初にルートタスクを中断する必要があります。ルートタスクが中断されると、将来のスケジュールされたルートタスクの実行はすべてキャンセルされます。ただし、現在実行中のタスクがある場合、これらのタスクと子孫タスクは、現在のバージョンを使用して引き続き実行されます。

注釈

タスクグラフの実行中にタスクによって呼び出されるストアドプロシージャの定義が変更された場合、現在実行中のタスクによってストアドプロシージャが呼び出されたときに、新しいプログラミングを実行できます。

たとえば、タスクグラフのルートタスクが中断されているが、このタスクのスケジュールされた実行がすでに開始されているとします。タスクグラフのすべてのタスクの所有者は、ルートタスクの実行中に子タスクによって呼び出される SQL コードを変更します。子タスクが実行され、ルートタスクが実行を開始したときに最新だったバージョンのタスクグラフを使用して、定義内の SQL コードが実行されます。ルートタスクが再開されるか、手動で実行されると、タスクグラフの新しいバージョンが設定されます。この新しいバージョンには、子タスクへの変更が含まれています。

タスクバージョンの履歴を取得するには、 TASK_VERSIONS Account Usageビュー (SNOWFLAKE 共有データベース内)をクエリします。

タスクの実行に失敗した後、タスクグラフを自動的に停止

必要に応じて、指定された数の連続したタスクの実行が失敗するかタイムアウトになると、タスクグラフを自動的に中断します。

タスクグラフのルートタスクに SUSPEND_TASK_AFTER_NUM_FAILURES = num パラメーターを設定します。パラメーターが 0 より大きい値に設定されると、タスクグラフ内の いずれかの 子タスクが連続して失敗するか、指定された回数だけタイムアウトになると、ルートタスクは自動的に中断されます。失敗またはタイムアウトした子タスクは中断されません。

失敗したタスクグラフの実行を自動的に再試行

タスクグラフの自動再試行回数を指定します。タスクグラフが FAILED の状態で完了した場合、Snowflakeは自動的に失敗したグラフの最後のタスクからタスクグラフを再試行することができます。

タスクグラフの自動再試行はデフォルトでは無効になっています。この機能を有効にするには、 TASK_AUTO_RETRY_ATTEMPTS0 より大きい値に設定します。

タスクグラフで依存タスクを表示する

ルートタスクの子タスクを表示するには、 TASK_DEPENDENTS テーブル関数をクエリします。タスクグラフ内の すべての タスクを取得するには、関数を呼び出すときにルートタスクを入力します。

また、 Snowsight を使ってタスクグラフを管理・表示することもできます。詳細については、 Snowsight でタスクとタスクグラフを表示する をご参照ください。

タスクグラフのリリースとクリーンアップ

ファイナライザータスクは、タスクグラフが使用するリソースのリリースとクリーンアップを処理します。ファイナライザータスクは、タスクグラフが実行された場合に実行が保証され、すべてのシナリオで適切なリソースのクリーンアップと必要なステップの完了が保証されます。たとえば、タスクグラフの実行が中間テーブルを使用して処理対象のデータを追跡し、テーブルの行が消費される前に失敗した場合、次の実行で重複行が発生し、データが再処理されるため、実行時間が長くなることや、コンピューティングリソースが浪費されることがあります。ファイナライザータスクは、必要に応じて行を削除したり、テーブルを切り詰めたりすることで、この問題に対処できます。

ファイナライザータスクは、タスクグラフ内の他のタスクと同じように動作しますが、次の違いがあります。

  • ファイナライザタスクは常にルートタスクと関連付けられます。各ルートタスクにはファイナライザタスクを1つのみ指定でき、ファイナライザタスクは1つのルートタスクのみに関連付けることができます。

  • ファイナライザータスクは、現在のタスクグラフの実行で他のタスクが実行中またはキューに入っておらず、グラフ内の少なくとも1つのタスクが実行を開始している場合にのみスケジュールされます。グラフがスキップされた場合(例えば、ルートタスクがスキップされた場合)、ファイナライザータスクは実行されません。ALLOW_OVERLAPPING_EXECUTION がtrueの場合、ファイナライザータスクは他のタスクと同じように動作し、他に進行中のタスクグラフの実行があったとしてもスケジュールされます。

  • ファイナライザタスクには子タスクを指定できません。ファイナライザタスクを先行タスクにしようとするコマンドは失敗します。ファイナライザタスクの作成には FINALIZE キーワードを含める必要がありますが、これは SCHEDULEAFTER キーワードの両方と互換性がありません。

ファイナライザタスクを作成するには、 FINALIZE キーワードを使用してタスクを作成し、ルートタスクとの関係を設定します。

CREATE TASK <TASK_NAME> ...
... FINALIZE = <ROOT_TASK_NAME>
Copy

詳細については、 CREATE TASK をご参照ください。