これでAWS Lambdaで動作するCommon Lispランタイムを実装したが,これを強化して,ハンドラを介してシステム内にある任意の関数を呼び出せるようにしたので紹介する.
この機能もリポジトリに入れてある.
また,この機能の実装は以下を参考にした.
[http://y2q-actionman.hatenablog.com/entry/2018/12/06/AWS_Lambda%E3%81%AE_Custom_Runtime%E3%81%A8%E3%81%97%E3%81%A6_Common_Lisp%28sbcl%29%E3%82%92%E4%BD%BF%E3%81%86:title]
関数を指定する
ハンドラで関数を指定するには,完全修飾した関数名をハンドラに与える.例えばfoo
パッケージのhoge
関数を指定するにはfoo:hoge
と記述する.非公開の関数を指定するにはfoo::hoge
のように指定する.
関数にはLambdaにリクエストしたbodyが引数として渡ってくる.これを処理して文字列を返すと,Lambdaのリクエストに値を返すことができる.
上掲のスクショではCL-USER:IDENTITY
(引数をそのまま返す標準関数)を指定し,そのままリクエストしたbodyを返している.
AWS LambdaでCommon Lispを実行し,ロードされたシステムの任意の関数を呼び出せるようになった.
実装
主要な部分は以下の通り.
(defun handler->function (handler-string) "Returns function object designated by HANDLER-STRING, formatted in \"PACKAGE:SYMBOL\" form. Package name cannot be omitted." (let* ((split (multiple-value-list (cl-ppcre:scan-to-strings "([^:]+)::?(.+)" handler-string))) (pkg-name (string-upcase (elt (cadr split) 0))) (func-name (string-upcase (elt (cadr split) 1))) (pkg (find-package pkg-name))) (if pkg (find-symbol func-name (find-package pkg)) nil))) (defun default-handler (content) "Only returns message." (declare (ignorable content)) "Handler not found.") (defun get-handler (handler) "Returns function object from string using HANDLER->FUNCTION. When symbol not found or error occurred, DEFAULT-HANDLER is returned." (handler-case (or (handler->function handler) #'default-handler) (error () #'default-handler))) (defun main-loop (handler) "Main loop processes lambda requests. Specify function designator with HANDLER." (declare (ignorable handler)) (let ((next-endpoint (format nil "http://~A/2018-06-01/runtime/invocation/next" *aws-lambda-runtime-api*))) (loop for (body status headers . nil) = (multiple-value-list (dex:get next-endpoint)) as request-id = (gethash "lambda-runtime-aws-request-id" headers) as response = (funcall (get-handler handler) body) as response-endpoint = (format nil "http://~A/2018-06-01/runtime/invocation/~A/response" *aws-lambda-runtime-api* request-id) do (dex:post response-endpoint :content response))))
今後の展望
- status codeを関数に渡せるようにする?
- 成功させず関数がエラーを返せるようにする?
- 既存のシステムをLambda化するラッパーを実装する?