Могу ли я создать и заполнить таблицу dynamicodb в одной функции Lambda? - PullRequest
0 голосов
/ 10 июля 2019

По сути, мой код состоит из двух частей, обе работают самостоятельно, но не вместе. Поэтому я думаю, что у меня есть проблема с синтаксисом.

Первая часть создает таблицу, вторая часть заполняет ее. Проблема в том, что обе части разделяют переменную имени таблицы.


   import os
   import boto3
   import botocore.session

   region = os.environ.get('AWS_DEFAULT_REGION', 'us-east-2')
   session = botocore.session.get_session()
   dynamo = session.create_client('dynamodb', region_name=region) 


   s3 = boto3.client('s3')
   dynamodb = boto3.resource('dynamodb')

   def lambda_handler(event, context):

    bucket = event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']

    obj = s3.get_object(Bucket=bucket, Key=key)

    rows = obj['Body'].read().decode("utf-8"). split ('\n')

    table = dynamodb.Table(key)
    dynamodb.create_table(
    TableName=key,
    KeySchema=[
        {
            'AttributeName': 'first',
            'KeyType': 'HASH'  #Partition key
        },
        {
            'AttributeName': 'last',
            'KeyType': 'RANGE'  #Sort key
        }
    ],
    AttributeDefinitions=[
        {
            'AttributeName': 'first',
            'AttributeType': 'S'
        },
        {
            'AttributeName': 'last',
            'AttributeType': 'S'
        },

    ],
    ProvisionedThroughput={
        'ReadCapacityUnits': 5,
        'WriteCapacityUnits': 5
        }
    )
   # Wait for the table to exist before exiting
    print('Waiting for', key, '...')
    waiter = dynamo.get_waiter('table_exists')
    waiter.wait(TableName=key)
    with table.batch_writer() as batch:
        for row in rows:

            batch.put_item(Item={

                'first':row.split(',')[0],
                'last':row.split(',')[1],
                'age':row.split(',')[2],
                'date':row.split(',')[3]

            })

Это работает как лямбда-функция всякий раз, когда CSV сбрасывается в мое ведро s3.

После запуска он успешно создает таблицу, но не заполняет ее. Окончание с: «Задание истекло через 3,00 секунды» Он запускается снова через несколько секунд и возвращает «Таблица уже существует», но остается пустой.

Если я запускаю только часть batch_writer, она будет заполнять таблицу, пока она уже существует.

1 Ответ

1 голос
/ 10 июля 2019

Короткий ответ: новая таблица обычно занимает около секунды, чтобы стать активной, а Waiter.TableExists использует интервал опроса по умолчанию, равный 20 секундам , что приводит к превышению времени ожидания лямбда-функции.

Но что на самом деле происходит?

Внутренне, Waiter.TableExists работает примерно так же, как этот псевдокод. (Я упустил обработку ошибок и другие детали для простоты.)

function waitForTable(tableName):
    while true:
        if (dynamodb.describeTable(tableName).status == active):
            return
        else:
            sleep 20 seconds

Сразу после создания таблицы вы запускаете официанта. Когда официант звонит describeTable, он видит, что стол еще не активен, поэтому он ждет 20 секунд. Ваш лямбда-тайм-аут установлен на 3 секунды, поэтому через 3 секунды (до того, как официант снова вызовет describeTable) ваша лямбда-функция будет прервана. (Это то, что означает сообщение «Тайм-аут задачи».)

Затем, когда ваша лямбда-функция повторяется, таблица становится активной, поэтому, когда ваша лямбда-функция достигает вызова dynamodb.create_table(...), DynamoDB ответит ошибкой, поскольку таблица уже существует. (Следовательно, сообщение об ошибке «Таблица уже существует».)

Как это исправить?

Есть несколько вещей, которые вы можете сделать, чтобы исправить это, и «наиболее правильное» решение, вероятно, состоит в том, чтобы сделать все из них.

  1. Вы можете установить время задержки официанта на меньшее число, например 1 секунду, например: waiter.wait(TableName=key, WaiterConfig={'Delay': 1})
  2. Вы можете увеличить время ожидания вашей лямбда-функции. Комбинация создания таблицы, чтения файла S3 и записи всего этого в DynamoDB может занять более 3 секунд. Выберите число, которое дает вашей лямбда-функции время для восстановления, если запрос необходимо повторить. Если ваша функция работает с файлом, содержащим только 1-2 строки, но не работает с файлами большего размера, я советую попробовать 5 секунд, а если это не удастся, увеличьте до 10 секунд. Если файлы могут быть очень большими, вам следует рассмотреть возможность использования чего-то иного, чем лямбда.
  3. Предполагая, что вас не беспокоит перезапись данных в ранее существующей таблице, вы должны проверить, существует ли таблица, прежде чем пытаться ее создать (или попытаться создать ее и игнорировать ResourceAlreadyInUseException, который возникает, если это уже существует). См. Этот другой ответ SO для Как проверить, существует ли таблица DynamoDB , который объясняет несколько способов проверить, существует ли таблица, включая примеры кода для каждого.
...