Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
AWS SDKのClientはFactory経由で作ろう
Search
TomoyaIwata
September 26, 2023
Programming
1
930
AWS SDKのClientは Factory経由で作ろう
「緊急開催!サーバーレス座談会 in JAWS-UG 大阪」にてLTさせて頂いた際の資料です
https://jawsugosaka.doorkeeper.jp/events/162714
TomoyaIwata
September 26, 2023
Tweet
Share
More Decks by TomoyaIwata
See All by TomoyaIwata
Aurora DSQLはサーバーレスアーキテクチャの常識を変えるのか
iwatatomoya
1
1.7k
これでLambdaが不要に?!Step FunctionsのJSONata対応について
iwatatomoya
2
6k
Qdrantでベクトルデータベースに入門してみよう
iwatatomoya
0
1.4k
詳解 AWS Lambdaコールドスタート
iwatatomoya
1
2.9k
真のサーバーレスへ向けたAuroraの進化Aurora Limitless Database
iwatatomoya
1
4.9k
OpentelemetryでアプリケーションのObservabilityを強化しよう
iwatatomoya
0
1.2k
AWS Lambdaは俺が作った
iwatatomoya
2
2.9k
SnapStartの未来についての期待と妄想
iwatatomoya
1
1.4k
実例から学ぶ! AWSを活用したシステム開発の勘所
iwatatomoya
1
3.4k
Other Decks in Programming
See All in Programming
AI 時代だからこそ抑えたい「価値のある」PHP ユニットテストを書く技術 #phpconfuk / phpcon-fukuoka-2025
shogogg
1
430
オフライン対応!Flutterアプリに全文検索エンジンを実装する @FlutterKaigi2025
itsmedreamwalker
2
200
MCPサーバー「モディフィウス」で変更容易性の向上をスケールする / modifius
minodriven
8
1.5k
しっかり学ぶ java.lang.*
nagise
1
350
2026年向け会社紹介資料
misu
0
170
『実践MLOps』から学ぶ DevOps for ML
nsakki55
2
350
Module Harmony
petamoriken
1
270
SidekiqでAIに商品説明を生成させてみた
akinko_0915
0
130
イベントストーミングのはじめかた / Getting Started with Event Storming
nrslib
1
440
CSC509 Lecture 11
javiergs
PRO
0
310
AIエージェントでのJava開発がはかどるMCPをAIを使って開発してみた / java mcp for jjug
kishida
4
620
Querying Design System デザインシステムの意思決定を支える構造検索
ikumatadokoro
1
1.1k
Featured
See All Featured
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.8k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
658
61k
Making the Leap to Tech Lead
cromwellryan
135
9.6k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
31
2.7k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Building Applications with DynamoDB
mza
96
6.8k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
15k
Building a Scalable Design System with Sketch
lauravandoore
463
33k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
36
6.1k
Optimizing for Happiness
mojombo
379
70k
The Language of Interfaces
destraynor
162
25k
How to Think Like a Performance Engineer
csswizardry
28
2.3k
Transcript
AWS SDKのClientは Factory経由で作ろう クラスメソッド株式会社 岩⽥ 智哉 1
2 ⾃⼰紹介 l クラスメソッド株式会社 サーバーサイドエンジニア l 2023 Japan AWS Top
Engineer l 2023 Japan AWS All Certifications Engineer l 前⼗字靭帯再建⼿術リハビリ中 岩⽥ 智哉
3 ⾔いたいこと AWS SDKのClientは Factory経由で作ろう
4 LambdaとEC2/ECSの違い リクエストとコンピューティング環境がN:1 リクエストとコンピューティング環境が1:1
5 リクエストとコンピューティング環境が1:1だと… ソケット ソケット ソケット ソケット DynamoDB等のAWSサービス ソケット ソケット Lambda実⾏環境で⽣成するソケットは1つで⼗分
(なことが多い)
6 これらを意識すると AWS SDKのClientの扱いが 最適化できる
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'})
8 何が良くないのか︖
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'})
10 そうはいっても • 現実世界のアプリはもっと複雑。呼び出し階層も深くなる • 呼び出し先の呼び出し先の呼び出し先…にclientを伝搬するのは⾯倒 • clientの処理化処理はもっと⾊々やることがある 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'})
11 提案 Factoryクラスを使おう︕
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
13 Factoryクラスの追加実装例 • タイムアウト値の調整 • デフォルト値はLambda実⾏環境の設定値としては不適切 • connect_timeout:60, read_timeout:60 •
Event Systemを利⽤したフックの登録 • API呼び出し前にパラメータをクラス変数に保存 • 例外キャッチ時にクラス変数に保存したパラメータをログ出⼒ • ⾮シングルトンなclientクラス⽣成処理 • たまにはPromise.All的な実装が必要になることもある
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クラ スを引き回さなくて良くなる
15 Provisioned Concurrency利⽤時の注意 Boto3ClientFactory.get_singleton_client('dynamodb’) def handler(event, context): … Init処理の中でclientクラスの⽣成を「空打ち」しておく
16 初回のClientクラス⽣成処理は重い https://github.com/boto/botocore/blob/40d6219947f4d047088cbeb80f8f222f599f9c7c/botocore/loaders.py • 初回のclientクラス⽣成時はJSONファイルを読み込んで動的にクラスを⽣成するので「重い」 • 2回⽬以後はキャッシュを使う • Init処理の中でclientクラス向けのキャッシュを「暖気」することでProvisioned Concurrencyに最適化
https://github.com/boto/botocore/blob/40d6219947f4d047088cbeb80f8f222f599f9c7c/botocore/data/dynamo db/2012-08-10/service-2.json
17 以上 ありがとうございました
18