Автор оригинала: Konstantin Shilovsky.
Облачные сервисы предназначены для того, чтобы облегчить нашу жизнь, избавив нас от сложности управления инфраструктурой. По крайней мере, они обещают это сделать.
Пытаясь удовлетворить максимально возможное количество клиентов различных размеров и с различными бизнес-моделями, официальная документация и руководства иногда не имеют простых вариантов использования, которые могут быть достаточными для небольших компонентов системы.
Одним из самых популярных сервисов AWS является S3. Его применение в организации может варьироваться от простого хранилища конфигураций до озера данных, содержащего огромные объемы информации.
S3 тесно интегрирован с другими сервисами AWS и фактически позволяет отправлять уведомления SNS, SQS или Lambda, когда изменения происходят в корзине S3.
Зачем вам нужен какой-либо дополнительный механизм уведомления, если вы просто хотите знать, когда новый файл добавляется в корзину?
Похоже, что настройка канала уведомлений между S3 и потребительскими службами не так проста.” Например, приложение Rails может использовать SNS в качестве канала уведомлений, но сервер Jenkins будет работать только через SQS. Кроме того, потребительские службы могут предъявлять различные требования к уведомлениям.
Из трех служб, упомянутых выше, Lambda кажется идеальным настраиваемым прокси-сервером между S3 и вашей системой. В этом посте я покажу, как легко создать настраиваемый сервис уведомлений с помощью AWS Lambda.
Потребительское обслуживание
Предположим, у нас есть служба аналитики, которая выполняет некоторые вычисления и сохраняет результаты в S3. Результаты должны быть импортированы в базу данных серверного приложения, чтобы их можно было представить пользователям.
Поскольку мы хотели бы избежать каких-либо проблем с планированием, цель состоит в том, чтобы сделать всю систему более реактивной. По этой причине мы хотели бы сообщить бэкенду, когда новые результаты будут готовы к использованию.
Написание функции
Предполагая, что у нас есть ведро, в котором появятся новые результаты, давайте добавим лямбда-функцию, которая будет обрабатывать входящие события.
События S3 имеют довольно сложную структуру, но, к счастью, AWS Lambda предоставляет тестовое событие, которое поможет нам в разработке и тестировании. Я буду использовать Python для кода функции, но, конечно, JavaScript и Java также поддерживаются.
Код для лямбда-функции можно разделить на 3 модуля:
- event_parser.py — извлекает путь к файлу из события S3.
- notifier.py — отправляет уведомление потребителю о новом или измененном файле.
- main.py — главный контроллер функции, вызывающей два других модуля.
event_parser состоит всего из одного метода, который извлекает путь к файлу, добавленному в S3. Несмотря на то, что событие, отправленное S3, будет содержать список “записей” (событий), я решил сохранить модуль простым и разрешил принимать только одно событие. Именно поэтому вы увидите итерацию списка событий в main.py позже.
def extract_s3_path(event): key = event['s3']['object']['key'] bucket = event['s3']['bucket']['name'] return f"s3://{bucket}/{key}"
Я пропущу код для тестов здесь, но вы можете найти их в репо .
notifier.py не знает о самом потребителе. Он просто отправляет запрос, построенный на основе параметров потребителя.
import requests import logging logger = logging.getLogger() def notify(consumer, s3_path): request = _build_request(consumer, s3_path) logger.info(f"Recepient: {request['url']}\nBody: {request['body']}") requests.post(request['url'], json=request['body'], auth=request['auth']) def _build_request(consumer, s3_path): return { 'url': consumer['url'], 'auth': (consumer['username'], consumer['password']), 'body': {'s3_path': s3_path} }
main.py собирает конфигурацию для потребителя и вызывает notifier с помощью пути s3, проанализированного event_parser .
import os import notifier import event_parser def handle(s3_event, context): consumer = _get_consumer() for event in s3_event['Records']: s3_path = event_parser.extract_s3_path(event) logger.info(f"Extracted path {s3_path}") notifier.notify(consumer, s3_path) def _get_consumer(): return { 'url': os.getenv('CONSUMER_URL'), 'username': os.getenv('CONSUMER_USERNAME'), 'password': os.getenv('CONSUMER_PASSWORD') }
Обратите внимание, что я использовал переменную среды для указания конечной точки. Это добавляет немного гибкости. Например, вы можете использовать RequestBin для проверки всех заголовков и содержимого тела в режиме разработки и использовать реальную конечную точку в рабочей среде.
Очевидно, что учетные данные также задаются с помощью переменных среды. Кроме того, я вставил некоторые выходные данные журнала, чтобы следить за выполнением функции в CloudWatch . Ссылку на журналы можно найти непосредственно в консоли AWS Lambda функции.
Настройка функции
Как я уже упоминал ранее, я добавил автоматические тесты, чтобы убедиться, что функциональность покрыта. Кроме того, вы обязательно запустите функцию с помощью события лямбда-теста, чтобы убедиться, что все работает так, как ожидалось.
Если вы еще не знакомы с AWS, вы можете легко добавить свою первую функцию, следуя этому учебнику .
Ниже приведены некоторые скриншоты, демонстрирующие, как следует настраивать переменные среды и тестовое событие.
Переменные среды Конфигурация тестового события
Добавление триггеров функций
Для того, чтобы функция была выполнена, нам нужно добавить триггеры к событиям S3. AWS Lambda предоставляет простой способ сделать это. Просто перейдите в раздел Триггеры панели мониторинга вашей функции и следуйте пошаговым инструкциям.
Вот как это выглядело для меня на последнем шаге: Настройка триггера S3
Стоит отметить, что событие S3 Multipart имеет решающее значение, если вы планируете загружать большие файлы. Мой опыт показывает, что AWS считает файлы размером более 10 МБ большими.
Теперь вы можете проверить выполнение функции, добавив или обновив файл в указанном выше ведре S3. Вы можете использовать какой-либо тестовый URL-адрес или CloudWatch logs для проверки результатов выполнения.
Вывод
Приведенной выше реализации недостаточно, чтобы охватить все варианты использования вашей системы уведомлений. Для более сложной логики обработки событий вы, скорее всего, предпочтете SQS.
Тем не менее, эта услуга служит единственной цели и имеет несколько преимуществ:
- Использует REST в качестве унифицированного интерфейса для уведомлений
- Устраняет сложность настройки SNS и SQS на стороне потребителя
- Имеет простой механизм аутентификации, который является расширяемым
- Позволяет анализировать и предварительно обрабатывать события S3
Чтобы сделать производство услуг готовым, вам нужно будет добавить немного больше гибкости. В следующем посте я продемонстрирую, как эту функцию можно расширить, чтобы поддерживать несколько типов уведомлений и потребителей.
Вы можете найти полный проект здесь .