背景
aws-samがどうやら使いにくいという噂がちらちら聞こえたのでどういうことか調べてみました。
一番の悩みは共通処理を書きにくいのでどうしても各ハンドラーにコピペの嵐をしてしまっているとのことです。(え!
調査
これはlambda-layerを使えば一瞬で解決。はい終了。
かと思ったら、そうでもなくてパス体系がローカルとlambda上でだいぶ変わってしまうことでうまくlambda-layerを使えないとのこと。
例えば、以下のようなフォルダ構成の場合。
├── handlers(lambda-function)
│ └── create_user
│ ├── app.py
│ └── requirements.txt
├── layers(lambda-layer)
│ ├── db_layer
│ │ ├── models
│ │ │ └── user.py
│ │ ├── setting.py
│ └── lib_layer
│ ├── lambda_common.py
│ ├── log_config.py
│ ├── requirements.txt
│ └── setup.py
ローカルでhandlers.create_user.app
からdb_layer.models.user
をimportする場合。
from layers.db_layer.models import user
となると思います。ただ、これをlambdaにのっけたときとかsam local start-api
で実行するとインポートエラーがおきます。
理由としては、lambda-layerは実行環境の/opt/python/
以下に配置されるためです。
この場合のインポート方法はpip installしたパッケージを使うのと似ています
。。ということは、解決の方法としてはローカルでlayersをそれぞれパッケージとしてインストールすればいいと仮説を立てました。
仮説検証
1. layersのインストール
最低限の事だけ書いたsetup.pyを用意して(以下、例)
from setuptools import setup
setup(
name='db_layer',
version='0.1.1',
)
pipenv install -d -e layers/db_layer layers/lib_layer
を実行すると
Pipfileが以下のようになり、他の人がpipenv sync -d
とかをやってくれれば環境が整うようになりました。
[dev-packages]
(略)
db-layer = {editable = true, path = "./layers/db_layer"}
lib-layer = {editable = true, path = "./layers/lib_layer"}
[requires]
python_version = "3.8"
2. import方法の変更
先ほどのローカルでのインストール方法を
from layers.db_layer.models import user
以下のように変更
from models import user
以下の二つを確認。
- unittestを実行してimport失敗しないこと
-
sam local start-api
を実行して、正常に動くこと
結論
pythonのlambda-layerはローカルでインストールすればうまくパス周りの整合性がとれて、開発は捗ります。
デバッグもテストもしやすいし、samとはうまく付き合っていけそうだなという所感です。
それ踏まえてのレポジトリを貼っておきます。pythonで裏側作る際に参考程度に使っていただけると報われます。
※なにか不具合あっても補償はできませんが、質問やお問い合わせ、改善要望はお待ちしております。