AWS
redshift
python3
lambda

AWS LambdaでPython3でpsycopg2でRedshiftへ接続する

やりたいこと

・S3にunloadクエリをputするとLambdaで拾ってRedshiftに流すようなサーバレスな処理を作りたい
・Python3でやりたい。

記事で割愛していること

  • VPCの設定(ネットワーク的にLambdaとRedshiftが疎通していること)
  • Lambdaの基本設定(VPCや、トリガーの設定)

手順

Python3のインストール

Python3でやりたい。その辺にあったAmazon Linuxにて

sudo yum install python36

psycopg2の準備

以下のコマンドで、-t で指定した場所にpsycopg2が設置される。

pip-3.6 install psycopg2 -t ./

ソースコードの作成

vi lambda_function.py

接続⇒実行までの超最低限サンプル

lambda_function.py
import psycopg2

def lambda_handler(event, context):
    try:
        connection = psycopg2.connect(port=5439, host="(VPC内のRedshiftのホスト)", database="XXXX", user="XXXX",password="XXXX")
        with connection.cursor() as cur:
            cur.execute("※ unloadクエリ ");
        return "test"
    except Exception as e:
        print(e)
        raise e

デプロイパッケージの作成

参考:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html

解凍したらディレクトリは挟まず、直接 lambda_function.pyと、pipで取得したpsycopg2/のディレクトリが出てくるように圧縮

lambda_function.py
psycopg2/

ファイル名は任意。
作成したものをコードエントリタイプ「.ZIPファイルをアップロード」よりアップ。

すごい

デプロイパッケージでアップロードしたあとで、「コードをインラインで編集」が使える。
zipファイルと同期が取れれなくなるが開発にはとても便利。

やって分かった事

Lambdaのタイムアウトになっても、unloadクエリの実行が開始されていればunload自体はRedshift上で処理は続くようなので、5分以上掛かるクエリであってもこの仕組みだと問題なさそう。やった!
ただし、このあたりはコンテナが破棄されなければ、みたいな話かなとも予想される。
どのみちクリティカルな処理をやるつもりは無いので深追いせず。

エラー変遷

Unable to import module 'lambda_function': No module named 'psycopq2'

今回使うパッケージ名は psycop"g"2 である...
コピペをすれば良い、というものではないというインターネットの罠。
 

Unable to import module 'lambda_function': No module named 'psycopg2._psycopg'

手元のWindows10のGit Bashで作業をしていたが、WindowsのGit Bashで pip install をすると
Windows用のパッケージとなってしまい、LinuxであるLambda上で動かないというのが原因だった。
このため、psycopg2のパッケージだけLinuxで用意するという手順を踏んでいる。
 

could not connect to server: Connection timed out

普通にPort指定を忘れていたため。
なお、psycopg2はデフォルトだとportは5432となり
Redshiftはデフォルトだとportは5439なので、Portの指定は必須な可能性が限りなく高い。
 

FATAL: password authentication failed for user "XXXX"

複雑なパスワードがPython上で上手くエスケープできなかったため。