0
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?

More than 1 year has passed since last update.

Prefect2で、リソース確保・クリーンアップのタスクをwith構文で実行する

Last updated at Posted at 2023-02-15

Prefectを使って、「EC2インスタンスを立ち上げて、シェルスクリプトを実行し、処理が終わったらシャットダウンする」ようなflowを実行しています。

こちらの記事を書いたPrefectの導入時点では、次のようにtry ~ finally で実行し、「シェルコマンドでエラーが起きた場合でもEC2インスタンスをシャットダウンする」ような処理を実現していました。

from tasks import run_ec2_instance, execute_commands, terminate_ec2_instance

@flow
def sample_flow():
    instance_id = run_ec2_instance(
        image_id="ami-******", # 自作のAMI
        instance_type="t2.micro",
        instance_profile='SSMInstanceRole', # ssmで接続するため、最低限この権限が必要
    )

    try:
        execute_commands(
            instance_id=instance_id,
            commands=["echo 'hello task1'"],
            terminate_after=30,
        )
        ...

    finally:
        terminate_ec2_instance(instance_id)

if __name__ == "__main__":
    sample_flow()

ただ、「How to clean up resources used in a flow?」にある通り、こういうリソースの確保、解放の処理は、Pythonの通常の関数(open等)のようにコンテキストマネージャ(with文)で大幅に簡略化できるようです。(ドキュメントから見つけられずにできないと思いこんでいただけでした)

次のようなコンテキストマネージャーを用意すると、

import contextlib

@contextlib.contextmanager
def setup_ec2_instance(image_id: str, instance_type: str, instance_profile: str):
    """EC2インスタンスのリソースを準備する。

    Args:
        image_id (str): AMIのID
        instance_type (str): インスタンスタイプ
        instance_profile (str): インスタンスプロファイル

    Yields:
        str: 起動したEC2インスタンスのID
    """
    instance_id = run_ec2_instance(image_id=image_id, instance_type=instance_type, instance_profile=instance_profile)
    try:
        yield instance_id
    finally:
        terminate_ec2_instance(instance_id=instance_id)

次のように、いつものPythonで見かける感じにスッキリできます。これで毎回try~finallyを書く必要が無くなりました🙌

from tasks import run_ec2_instance, execute_commands, terminate_ec2_instance

@flow
def sample_flow():
    with setup_ec2_instance(
        image_id="ami-******", # 自作のAMI
        instance_type="t2.micro",
        instance_profile='SSMInstanceRole', # ssmで接続するため、最低限この権限が必要
    ) as instance_id:
        execute_commands(
            instance_id=instance_id,
            commands=["echo 'hello task1'"],
            terminate_after=30,
        )

if __name__ == "__main__":
    sample_flow()

How to clean up resources used in a flow?」を読むと、Prefect 1の時点ではコンテキストマネージャ用の専用の機能が用意されていたのですが、Pythonの標準的な方法(contextlib)で実装できるように変更されたようですね。

0
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
0
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?