В этом руководстве мы интегрируем SQS для отправки сообщения в лямбда-функцию в проекте Amplify с использованием Cloudformation.

Ссылка на репозиторий git: https://github.com/wahmd/sqs-with-lambda-using-aws-amplify

Интегрируйте пользовательский ресурс (SQS) с функцией amplify, чтобы отправка сообщения в очередь вызывала лямбда-выражение с сообщением о событии в теле.
Получите ту же полезную нагрузку внутри лямбда-функции.

https://user-images.githubusercontent.com/74547936/146831301-27c3f6eb-c6a3-4d4a-98be-10d6f96aac77.mp4

Оглавление

  • Почему этот учебник
  • Базовая настройка проекта (из документации amplify):
  • Добавьте функцию Lambda с помощью Amplify CLI:
  • Добавление очереди SQS fifo
  • Связывание очереди SQS с Lambda
  • Добавление параметра (с использованием значения из другого стека)
  • Неявный способ добавления параметра:
  • **<CATEGORY><RESOURCE_NAME><OUTPUTS_VARIABLE>**
  • Явный способ добавления параметра:
  • Добавить очередь как зависимость к лямбде (порядок создания ресурсов)
  • Рабочая демонстрация

Важный совет:

Если во время обучения вы вносите какие-либо изменения в файл cloudformation, шаблона или параметров, обязательно выполните amplify env checkout перед выполнением amplify push. В противном случае cli не обнаружит изменения в течение amplify status.

Почему этот учебник

SQS не генерируется клиентским интерфейсом amplify напрямую, как некоторые другие сервисы. например, мы можем добавить лямбду с помощью команды
amplify add function

Но для добавления SQS у нас нет такой команды, как amplify add queue и т. д.

Есть несколько способов добавить другие ресурсы, не поддерживаемые интерфейсом командной строки, в качестве Пользовательских ресурсов.

Amplify предоставляет два основных метода интеграции пользовательского ресурса в наше приложение Amplify.

  1. Используйте CDK для добавления пользовательских ресурсов AWS
  2. Используйте CloudFormation для добавления пользовательских ресурсов AWS

В первом вы можете написать свой пользовательский ресурс так же просто, как на Javascript, который cdk synth преобразуется в облачное формирование.
Во втором вы просто предоставляете облачное формирование, которое развертывается при усилении push.

Оба этих метода просто великолепны. Однако в своем недавнем проекте я нашел еще один способ, которым хочу поделиться с вами, ребята. В этом методе я создал SQS, используя расширенную структуру папок и облачное формирование, не создавая отдельную папку для пользовательских ресурсов (как в приведенных выше методах).

Не нашел много в Интернете, поэтому просто поделился этим здесь для учебных целей.

Базовая настройка проекта (из документации amplify):

Сначала нам нужно инициализировать базовый бэкэнд amplify.

Для этого выполните все шаги в Предварительных требованиях и Настройка проекта полного стека, чтобы инициализировать пустой бэкэнд amplify.

Добавьте функцию Lambda с помощью Amplify CLI:

Теперь мы можем начать с добавления лямбда-функции, которая будет использоваться для опроса из очереди fifo.
Вы можете добавить лямбда-выражение
amplify add function

Это создаст лямбда-функцию AWS, которая будет использоваться для обработки сообщений из очереди.

Теперь мы видим, что function handleOrder добавляется в папку amplify/backend.

Это присутствует локально, поэтому нам нужно amplify push его, чтобы эта лямбда создавалась в облаке.

После push теперь вы можете перейти в консоль aws и проверить это. (убедитесь, что вы выбрали свой регион при просмотре, поскольку лямбда — это сервис, основанный на регионе, и он будет присутствовать только в вашем регионе)

Эта папка backend содержит все ресурсы. Итак, если мы хотим добавить еще один (пользовательский) ресурс, нам нужно создать внутри него папку.

Добавление очереди SQS fifo

  • Создайте новую папку внутри папки backend и назовите ее queue. («очередь» не является зарезервированным словом, вы можете назвать что угодно, но вам также необходимо обновить и другие файлы — поясните позже в руководстве). Это категория
  • Создайте папку и назовите ее ordersQueue (это ресурс (очередь)).
  • В любой папке ресурсов должны быть эти два файла:
  • template.yml
  • parameters.json

Итак, создайте эти файлы.

Я использую yml для формирования облака.
в ресурсах добавьте ресурс типа SQS:Queue как

Resources:
  OrderQueue:
    Type: AWS::SQS::Queue
    Properties:
      FifoQueue: true
      ContentBasedDeduplication: true
      QueueName:
        Fn::Join:
          - ''
          - - orders-queue-
            - Ref: env
            - .fifo

Здесь я использую очередь «первым пришел, первым обслужен» (FIFO) с включенным ContentBasedDeduplication.

Это также будет динамически генерировать имя очереди на основе среды выполнения.
Подробнее о встроенной функции Fn:join можно прочитать в документации.

Нам также нужно прикрепить политику SQS к этой очереди с разрешениями на отправку, получение, удаление и другие действия, такие как:

SQSPolicy:
    Type: AWS::SQS::QueuePolicy
    Properties:
      Queues:
        - Ref: OrderQueue
      PolicyDocument:
        Statement:
          - Effect: Allow
            Principal: '*'
            Action:
              - SQS:SendMessage
              - SQS:ReceiveMessage
              - SQS:DeleteMessage
              - SQS:GetQueueAttributes
            Resource:
              Fn::GetAtt:
                - OrderQueue
                - Arn

Для простоты мы используем ‘*’. Эта политика позволяет всем участникам выполнять перечисленные действия в OrderQueue.
Вместо этого в реальном приложении следует включать в очередь только те ресурсы или учетные записи, которым необходим доступ.

Итак, теперь наш полный template.yml выглядит так:

AWSTemplateFormatVersion: '2010-09-09'
Description: >-
  {"createdOn":"Windows","createdBy":"Amplify","createdWith":"7.3.6","stackType":"queue-SQS","metadata":{}}
Parameters:
  env:
    Type: String
Resources:
  OrderQueue:
    Type: AWS::SQS::Queue
    Properties:
      FifoQueue: true
      ContentBasedDeduplication: true
      QueueName:
        Fn::Join:
          - ''
          - - orders-queue-
            - Ref: env
            - .fifo
  SQSPolicy:
    Type: AWS::SQS::QueuePolicy
    Properties:
      Queues:
        - Ref: OrderQueue
      PolicyDocument:
        Statement:
          - Effect: Allow
            Principal: '*'
            Action:
              - SQS:SendMessage
              - SQS:ReceiveMessage
              - SQS:DeleteMessage
              - SQS:GetQueueAttributes
            Resource:
              Fn::GetAtt:
                - OrderQueue
                - Arn       
Outputs:
  QueueURL:
    Description: URL of new Amazon SQS Queue
    Value:
      Ref: OrderQueue
  QueueARN:
    Description: ARN of new Amazon SQS Queue
    Value:
      Fn::GetAtt:
        - OrderQueue
        - Arn
  QueueName:
    Description: Name new Amazon SQS Queue
    Value:
      Fn::GetAtt:
        - OrderQueue
        - QueueName
  • Поместите пустой объект в parameters.json как:
    {}
  • Включите queue в папку backend-config. Потому что, если ваш ресурс не указан в backend-config, он не появится в amplify status и, следовательно, не будет отправлен в облако.
{
  "function": {
    "handleOrder": {
      "build": true,
      "providerPlugin": "awscloudformation",
      "service": "Lambda",
    }
  },
  "queue": {
    "ordersQueue": {
      "providerPlugin": "awscloudformation",
      "service": "SQS"
    }
  }
}
  • Теперь сохраните изменения
  • Сообщите CLI о нашей пользовательской категории и ресурсе, проверив текущую среду: amplify env checkout <env-name>
  • Повторите amplify push, чтобы получить очередь в облаке.
  • Мы можем видеть нашу очередь на консоли

  • Если все загружается в облако без проблем, вы можете перейти к следующей части.

Связывание очереди SQS с Lambda

Теперь у нас есть queue и handleOrder в облаке, но оба они не настроены. Мы настроили его таким образом, что если SQS получает сообщение, оно отправляется в лямбду как событие.
Это идеальный случай для типа EventSourceMapping, который в основном отображает событие из источника (кинез, SQS все, что создает событие и т. д.). к лямбда-функции.

Поэтому мы добавляем это в формирование облака нашей функции handleOrder в разделе Resources.

"LambdaFunctionSQSMapping": {
      "Type": "AWS::Lambda::EventSourceMapping",
      "Properties": {
        "BatchSize": 1,
        "Enabled": true,
        "EventSourceArn": {
          "Ref": "queueordersQueueQueueARN"
        },
        "FunctionName": {
          "Ref": "LambdaFunction"
        }
      }
    }

путь к файлу: amplify/backend/function/handleOrder/handleOrder-cloudformation-template.json

Здесь важными атрибутами, которые следует учитывать, являются:

  • EventSourceArn — это уникальный идентифицируемый номер источника, из которого будет поступать событие.
  • FunctionName — Имя функции, которая будет вызываться при наступлении события.

Добавление параметра (с использованием значения из другого стека)

Здесь у нас в настоящее время нет queueARN внутри этого файла. Мы можем получить к нему доступ, используя parameters и Outputs возможности стеков.
Мы экспортируем QueueARN из нашей очереди в ее template.yml.
Есть два способа использования параметров.

  • неявный — автоматически усиливать выбор, если соблюдается структура каталогов)
  • явный — определите, из какого именно ресурса, какое значение получите с помощью встроенных функций.

Неявный способ добавления параметра:

  • Включите параметр queueordersQueueQueueARN в лямбда-облако как:
"queueordersQueueQueueARN": {
      "Type": "String"
    }

Структура имени параметра очень важна, так как amplify автоматически выбирает ее, если используется правильно.

**<CATEGORY><RESOURCE_NAME><OUTPUTS_VARIABLE>**

Структура каталогов:

amplify 
  ├── backend
  │       ├── function
  │       │      └── handleOrder
  │       ├── queue
  │       │       └── ordersQueue
  │       │               ├── template.yml
  │       │               └── parameters.json

пример: очередь ордеровQueueQueueARN

Явный способ добавления параметра:

Наряду с неявным способом вы также определяете в parameters.json, откуда именно вы получите это значение.

  • Включить в файл amplify/backend/function/handleOrder/parameters.json
{
    "queueordersQueueQueueARN": {
        "Fn::GetAtt": ["ordersQueue", "Outputs.QueueARN"]
    }
}

Здесь GetAtt извлекает QueueARN из ресурса ordersQueue, который экспортируется из стека с использованием Outputs.

Добавить очередь как зависимость к лямбде (порядок создания ресурсов)

В backend-config все ресурсы выводятся и генерируются параллельно, если между ними нет зависимости.

Если мы попытаемся push запустить наше текущее приложение, мы получим сообщение об ошибке:
An error occur during the push operation: Template error: instance of Fn:GetAtt references undefined resource ordersQueue

Мы получаем это в parameters.json, когда пытаемся получить доступ к QueueARN из его экспорта.

orderQueue имеет номер undefined, и доступ к одному из его экспортов приводит к ошибке.

Почему orderQueue не определен?

Поскольку облако создает очередь и лямбду параллельно, но поскольку лямбда зависит от очереди (мы используем выходные данные очереди в лямбде), мы должны сообщить облаку, что создавать лямбда только тогда, когда очередь полностью создана и готова

Мы можем определить порядок, в котором ресурсы будут создаваться в облаке в backend-config.json, следующим образом:

  • обновить backend-config.json как:
{
  "function": {
    "handleOrder": {
      "build": true,
      "providerPlugin": "awscloudformation",
      "service": "Lambda",
      "dependsOn": [
        { 
          "category": "queue",
          "resourceName": "ordersQueue",
          "attributes": ["QueueARN"]
        }
      ]
    }
  },
  "queue": {
    "ordersQueue": {
      "providerPlugin": "awscloudformation",
      "service": "SQS"
    }
  }
}

Здесь, в dependsOn, мы определяем, что текущий ресурс не должен создаваться, если все ресурсы в массиве dependsOn не готовы, поскольку он имеет зависимость. Сначала создайте зависимые ресурсы, затем создайте исходный ресурс.

  • Do amplfiy env checkout <INSERT_YOUR_ENV>
  • Do amplify push -y

После успешного запуска у вас будет все готово для демонстрации.

Рабочая демонстрация

Мы видим, что отправка сообщения в очередь вызывает лямбду с сообщением о событии в теле.

  • ✅ Получите ту же полезную нагрузку внутри лямбда-функции.

https://user-images.githubusercontent.com/74547936/146826151-cc9d3e8e-9fd6-4f55-ae12-f1245b326e18.mp4

Если вам это понравилось, ⭐ этот репозиторий по адресу:
https://github.com/wahmd/sqs-with-lambda-using-aws-amplify