8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Supershipグループ Advent Calendar 2024Advent Calendar 2024

Day 4

Cloud Workflowsを使ってみて得たTips

Last updated at Posted at 2024-12-03

この記事は、Supershipグループ Advent Calendar 2024の4日目の記事になります。

はじめに

Google CloudのWorkflowsを業務で使用する機会があったため、そこで得た知見を共有したいと思います。
Workflows をあまり触ったことがない人向けです。

事例

今回は、GCSの任意のorigフォルダに動画をアップロードしたときに動画変換を行うワークフローをWorkflowsを使って実現しました。

柔軟なトリガーを使いたい時は Cloud Audit Logs 経由のイベントを指定する

さっそくWorkflowsというよりEventarcの話になりますが…。
GCSの任意のフォルダへアップロードしたときにトリガーを発火させたい場合は、Eventarcのパスパターンが有効でした。

例えば、今回の事例ではフォルダ orig を含むときに発火させたかったので、パスパターンは以下のようになりました。

/projects/_/buckets/バケット名/**/orig/*

このパスパターンですが、イベントタイプによって使用できない場合があります。
今回の事例でいうと、GCSをイベントプロバイダ、Workflowsをイベントの宛先とする場合、Eventarcトリガーで使用できるイベントタイプには以下の2種類があります。

  • Cloud Audit Logsイベント
  • 直接イベント

image.png
この2つについてパスパターンの適用可否を確認してみます。

Cloud Audit Logsイベントの場合は、pathPatternSupported: trueとありますので、パスパターンを適用できることがわかります。

gcloud eventarc providers describe cloudaudit.googleapis.com --location=asia-northeast1
displayName: Cloud Audit Logs
eventTypes:
- description: An audit log is created that matches the trigger's filter criteria.
  filteringAttributes:
  - attribute: methodName
    description: The identifier of the service's operation.
    required: true
  - attribute: resourceName
    description: The complete path to a resource. Used to filter events for a specific
      resource.
    pathPatternSupported: true <-
  - attribute: serviceName
    description: The identifier of the Google Cloud service.
    required: true
  - attribute: type
    required: true
  type: google.cloud.audit.log.v1.written
name: projects/プロジェクトID/locations/asia-northeast1/providers/cloudaudit.googleapis.com

一方で直接イベントの場合は、pathPatternSupported: trueが見当たらないので、パスパターンを適用できないことがわかります。

$ gcloud eventarc providers describe storage.googleapis.com --location=asia-northeast1
displayName: Cloud Storage
eventTypes:
- description: The live version of an object has become a noncurrent version.
  filteringAttributes:
  - attribute: bucket
    description: The bucket name being watched.
    required: true
  - attribute: type
    required: true
  type: google.cloud.storage.object.v1.archived
- description: An object has been permanently deleted.
  filteringAttributes:
  - attribute: bucket
    description: The bucket name being watched.
    required: true
  - attribute: type
    required: true
  type: google.cloud.storage.object.v1.deleted
- description: A new object is successfully created in the bucket.
  filteringAttributes:
  - attribute: bucket
    description: The bucket name being watched.
    required: true
  - attribute: type
    required: true
  type: google.cloud.storage.object.v1.finalized
- description: The metadata of an existing object changes.
  filteringAttributes:
  - attribute: bucket
    description: The bucket name being watched.
    required: true
  - attribute: type
    required: true
  type: google.cloud.storage.object.v1.metadataUpdated
name: projects/プロジェクトID/locations/asia-northeast1/providers/storage.googleapis.com

以上より、GCSでイベントプロバイダとしてパスパターンによる柔軟なトリガーを使いたい場合は、Cloud Audit Logs経由のイベントを指定する必要があります。
image.png

prefix指定のみできれば良い場合は、直接イベントで行う方法もあるようですね!

ちなみに2024年10月31日にPreview版になったEventarc Advancedの方が、より詳細な制御ができるそうですが、GCSはサポートされておらず、また東京リージョンでは使えませんでした。
image.png

サブワークフローは変数のスコープが分断される

公式ベストプラクティスにもある通り、サブワークフローを使用するとワークフローを分割することができ、ワークフローの複雑化を回避することができます。
可視化されるフロー図もサブワークフロー単位となるので実行の流れも追いやすくなります。
image.png
エラーハンドリングのような共通で使用するワークフローは、特にサブワークフローとして切り出すと良さそうです。

ただし変数のスコープが分かれるので、サブワークフローで使用する変数をparamsフィールドで受け取る必要があります。

Subworkflows do not have access to any variables from the main block of a workflow or other subworkflows. A subworkflow receives values passed in a call, and assigns those values to new variables in the subworkflow scope. Note that all step names in a subworkflow must be unique, even if they are in a scope.
https://cloud.google.com/workflows/docs/reference/syntax/variables#variable-scope

例えば、発生したエラーをFirestoreに格納したい場合、格納するdocument_pathを参照するためにエラーが発生するワークフローからdocument_pathを引き回す必要がありました。

main:
  params: [event]
  steps:
    - init:
        assign:
          - document_path: ...
    - call_convert_file:
        call: convert_file
        args:
          ...
          document_path: ${document_path}
    - call_upload_converted_file:
        call: upload_converted_file
        args:
          ...
          document_path: ${document_path}
    ...

convert_file:
  params: [..., document_path]
  steps:
    - post_convert:
        try:
          ...
        except:
          as: error
          steps:
            - known_error:
                switch:
                  - condition: ${error.body != null and error.body.status != null}
                    steps:
                      - store_known_error:
                          call: store_error
                          args:
                            error_code: ${error.body.code}
                            error_message: ${error.body.message}
                            document_path: ${document_path}
                          next: end
            - unknown_error:
                call: store_error
                args:
                  error_code: "unknown"
                  error_message: ${error.message}
                  document_path: ${document_path}
                next: end
    ...

upload_converted_file:
  params: [..., document_path]
  steps:
    ...

store_error:
  params: [error_code, error_message, document_path]
  steps:
    - init_store_error:
        assign:
          - project_id: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
    - store_error_to_firestore:
        call: googleapis.firestore.v1.projects.databases.documents.patch
        args:
          name: ${"projects/"+project_id+"/databases/(default)/documents/"+document_path}
          updateMask:
            fieldPaths:
              - "errorCode"
              - "errorMessage"
          body:
            fields:
              errorCode:
                stringValue: ${error_code}
              errorMessage:
                stringValue: ${error_message}
    - raise_error:
        raise:
          error_code: ${error_code}
          error_message: ${error_message}

サブワークフローはプログラミング言語の関数に似ていますが、グローバル変数のようには変数を使えないと思って分割を考える必要があります。

環境変数で環境差分を吸収する

各環境でアクセスするドメイン名やSecret Managerのシークレット名などが異なる場合は、環境変数を使用してYAMLの共通化を図ることができます。
env.prod.yaml や env.stg.yaml として保存しておき、--env-vars-file オプションでそのパスを指定すれば読み込むことができます。

$ gcloud workflows deploy WORKFLOW_NAME --env-vars-file ./env.prod.yaml

コンソール画面上からも確認、編集することができます。
image.png

環境変数をWorkflowsのコード上から参照するときは、sys.get_env()を使用します。

main:
  steps:
    - init:
        assign:
          - keyValue: ${sys.get_env("KEY1")}
    - returnResult:
        return: ${keyValue}

使用できる環境変数は最大で20個、4KiBまでです。

長時間実行には向いているが処理には向いていない

Workflowsは、実行可能な最長時間が1年と非常に長いため、タイムアウトを気にする必要がほとんどありません。
料金形態もステップごとの課金のため、長時間実行による課金はありません。
プロジェクトあたりの同時実行数も定期的に増加されており、現在では10,000となっています1

今回の事例では動画変換状態のポーリングをしていて変換には5〜10分以上かかるため、Cloud Functionsではタイムアウト時間 9分2 を超える恐れがありましたが、Workflowsではタイムアウトの心配をせずに済みました。

その一方で、Workflowsは、変数に512KBまでしかデータを持つことができません。

今回の事例では変換後の動画がS3に格納されており、それをGCSにアップロードする必要がありましたが、512KBまでしかデータを持つことができず、それ以前にHTTPレスポンスサイズも2MBまでなので、ダウンロード時点でエラーになってしまいました。
仕方ないので大人しく、アップロード処理のみCloud Functionsで実装しました。
他にも、割り当て(assign)できる変数の上限が50個であることも考慮する必要があります。

以下の記事でも言及されているように、基本的に処理はCloud Functionsに任せてワークフローの実装に集中するのが良さそうですね。

おわりに

Workflowsを使用してみて、Google Cloudサービスであれば認証情報を渡さずとも正しいロールが設定してあれば簡単にオーケストレーションできるのがやはり便利でした。
公式サンプルが充実しているのもありがたいですね。

最後に宣伝です。

Supershipではプロダクト開発やサービス開発に関わる人を絶賛募集しております。
ご興味がある方は以下リンクよりご確認ください。
Supership 採用サイト
是非ともよろしくお願いします。

  1. 日本語ドキュメントでは未更新のためか7,500になっているので注意: https://cloud.google.com/workflows/quotas?hl=ja#quotas

  2. https://cloud.google.com/functions/docs/configuring/timeout?hl=ja

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?