0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AWS Lambdaで「Function.ResponseSizeTooLarge」エラーが出たので対処した話

Last updated at Posted at 2019-10-06

環境

AWS LambdaとPythonでスクレイピング処理をマイクロサービス化する

上記記事で紹介している「headlessms」を利用する、下記のような「IDとパスワードでログインをして取得したクッキーを使って指定のURLから画像データをダウンロードし、そのバイナリを配列で取得して処理する」システムをAWS Lambdaで運用している。

lambda_main.py
import re,json,boto3,os
from base64 import b64decode

def lambda_handler(event, context):

    kms = boto3.client('kms')
    login_id = kms.decrypt(CiphertextBlob=b64decode(os.environ['login_id']))['Plaintext'].decode('utf-8')
    login_password = kms.decrypt(CiphertextBlob=b64decode(os.environ['login_password']))['Plaintext'].decode('utf-8')

    img_urls = []    
    img_urls = re.findall('https://bmimg.sample3.jp/image/chXXXXXXX/.+\.jpg',event['body'])

    input_event = {
        "body": open('func.py').read() \
                    .replace('__imgUrls__',str(img_urls)) \
                    .replace('__loginId__',login_id) \
                    .replace('__loginPassword__',login_password)
    }

    res = boto3.client('lambda').invoke(
        FunctionName = 'headlessms-aws-function-00',
        InvocationType = 'RequestResponse',
        Payload = json.dumps(input_event)
    )
    img_ary = json.loads(json.loads(res['Payload'].read())['body'])
func.py
import requests,json
from base64 import b64encode
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
def scrape_process(driver):

    driver.get('https://account.sample3.jp/login')
    WebDriverWait(driver, 5).until(ec.presence_of_all_elements_located)

    driver.find_element_by_id('input__mailtel').send_keys('__loginId__')
    driver.find_element_by_id('input__password').send_keys('__loginPassword__')

    submitButton = driver.find_element_by_id('login__submit')
    submitButton.click()

    session = requests.session()
    for cookie in driver.get_cookies():
        session.cookies.set(cookie['name'], cookie['value'])

    img_urls = __imgUrls__
    img_contents = []

    for url in img_urls:
        img_contents.append(b64encode(session.get(url).content).decode('utf-8'))

    return(json.dumps(img_contents))

事象

あるとき、いつもなら問題ないく動作している上記システムの自動実行がboto3.client('lambda').invokeの箇所で以下のようなエラーを出して不正終了していた。

{'errorType': 'Function.ResponseSizeTooLarge', 'errorMessage': 'Response payload size (9471685 bytes) exceeded maximum allowed payload size (6291556 bytes).'}

調査してみると、Lambda関数をRequestResponseタイプで呼び出したときに送受信されるデータのサイズ上限が6291556 bytes(約6MB)であり、超過した場合に発生するエラーとのこと。

そこで「headlessms」に送信されたURL数を確認してみると、いつもなら一度に10個程度の画像URL(img_urls)しか送信されないところ、今回のエラーが発生したときの処理では32個もURLが送信されていた。
いつもより送信するURL数が多かったため、「headlessms」側で6MBを超える画像が取得され、返送時にエラーとなっていたらしい。

解決

lambda_main.pyを以下のように修正し、画像URLの「headlessms」への送信は最大10個ずつとなるようにした。

modified_lambda_main.py
import re,json,boto3,os
from base64 import b64decode

def lambda_handler(event, context):

    kms = boto3.client('kms')
    login_id = kms.decrypt(CiphertextBlob=b64decode(os.environ['login_id']))['Plaintext'].decode('utf-8')
    login_password = kms.decrypt(CiphertextBlob=b64decode(os.environ['login_password']))['Plaintext'].decode('utf-8')

    img_urls = []    
    img_urls = re.findall('https://bmimg.sample3.jp/image/chXXXXXXX/.+\.jpg',event['body'])

    def split_list(l):
        for idx in range(0, len(l), 10):
            yield l[idx:idx + 10]
    img_urls_list = list(split_list(img_urls))

    img_ary = []
    for img_urls_within10 in img_urls_list:
        #画像URLから画像データ取得
        input_event = {
            "body": open('func.py').read() \
                        .replace('__imgUrls__',str(img_urls_within10)) \
                        .replace('__loginId__',login_id) \
                        .replace('__loginPassword__',login_password)
        }
    
        res = boto3.client('lambda').invoke(
            FunctionName = 'headlessms-aws-function-00',
            InvocationType = 'RequestResponse',
            Payload = json.dumps(input_event)
        )
    
        img_ary.extend(json.loads(json.loads(res['Payload'].read())['body']))

参考

https://forums.aws.amazon.com/thread.jspa?threadID=230229
https://www.stackery.io/blog/RequestEntityTooLargeException-aws-lambda-message-invocation-limits/
https://www.python.ambitious-engineer.com/archives/1843

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?