Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AWS SDKのClientは Factory経由で作ろう

TomoyaIwata
September 26, 2023

AWS SDKのClientは Factory経由で作ろう

「緊急開催!サーバーレス座談会 in JAWS-UG 大阪」にてLTさせて頂いた際の資料です

https://jawsugosaka.doorkeeper.jp/events/162714

TomoyaIwata

September 26, 2023
Tweet

More Decks by TomoyaIwata

Other Decks in Programming

Transcript

  1. 2 ⾃⼰紹介 l クラスメソッド株式会社 サーバーサイドエンジニア l 2023 Japan AWS Top

    Engineer l 2023 Japan AWS All Certifications Engineer l 前⼗字靭帯再建⼿術リハビリ中 岩⽥ 智哉
  2. 7 良くない例1 import boto3 class TableA: def __init__(self): self._client =

    boto3.client('dynamodb') def put_item(self, item): self._client.put_item(TableName='tableA', Item=item) class TableB: def __init__(self, client): self._client = boto3.client('dynamodb') def put_item(self, item): self._client.put_item(TableName='tableB', Item=item) def handler(event, context): table_a = TableA() table_a.put_item({'foo': 'bar’}) table_b = TableB() table_b.put_item({'hoge': 'fuga'})
  3. 9 よくある解決策 class TableA: def __init__(self, client): self._client = client

    def put_item(self, item): self._client.put_item(TableName='tableA', Item=item) class TableB: def __init__(self, client): self._client = client def put_item(self, item): self._client.put_item(TableName='tableB', Item=item) import boto3 client = boto3.client('dynamodb’) def handler(event, context): table_a = TableA(client) table_a.put_item({'foo': 'bar'}) table_b = TableB(client) table_b.put_item({'hoge': 'fuga'})
  4. 12 実装例(簡易版) import boto3 class Boto3ClientFactory: # ⽣成したclientクラスのインスタンスをクラス変数に保持しておく _clients =

    {} @classmethod def get_singleton_client(cls, service_name, **kwargs): # 対象サービスのclientクラスを⽣成済みならクラス変数のキャッシュから返却 # 複数リージョンを扱う場合はキャッシュキーにリージョンを含めるなど追加の考慮が必要 if service_name in cls._clients: return cls._clients[service_name] client = boto3.client(service_name, **kwargs) cls._clients[service_name] = client return client
  5. 13 Factoryクラスの追加実装例 • タイムアウト値の調整 • デフォルト値はLambda実⾏環境の設定値としては不適切 • connect_timeout:60, read_timeout:60 •

    Event Systemを利⽤したフックの登録 • API呼び出し前にパラメータをクラス変数に保存 • 例外キャッチ時にクラス変数に保存したパラメータをログ出⼒ • ⾮シングルトンなclientクラス⽣成処理 • たまにはPromise.All的な実装が必要になることもある
  6. 14 Factoryクラスの利⽤例 client = Boto3ClientFactory.get_singleton_client('dynamodb') def handler(event, context): table_a =

    TableA(client) table_a.put_item({'foo': 'bar'}) table_b = TableB(client) table_b.put_item({'hoge': 'fuga'}) def foo(): bar() def bar(): baz() def baz(): client = Boto3ClientFactory.get_singleton_client('dynamodb') table_a = TableA(client) table_a.put_item({'foo': 'bar'}) def handler(event, context): foo() タイムアウト値など適切に設定された clientクラスが1発で取得可能 呼び出し階層の深いところまでclientクラ スを引き回さなくて良くなる
  7. 18