Использование API Gateway WebSockets с Serverless Framework

Первоначально опубликовано на Serverless 21 декабря 2018 г.

Обновление: Начиная с версии 1.38, Serverless Framework поддерживает WebSockets в ядре. Нет необходимости в плагине! Прочтите объявление и инструкцию здесь.

Поскольку мы приближаемся к концу 2018 года, я невероятно рад объявить, что у нас в Serverless есть небольшой подарок для вас: Вы можете работать с Amazon API Gateway WebSockets в своих приложениях Serverless Framework прямо сейчас.

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

Во-первых, эта функция пока не поддерживается в AWS CloudFormation, хотя AWS публично заявила, что это произойдет в начале следующего года! Поэтому мы решили реализовать нашу первоначальную поддержку в виде плагина и не включать его в ядро до тех пор, пока не будет добавлена официальная поддержка AWS CloudFormation.

Во-вторых, синтаксис конфигурации должен быть довольно близким, но мы не обещаем, что все, что будет реализовано с его помощью, будет перенесено после поддержки ядра. После добавления поддержки ядра AWS CloudFormation вам придется заново создать ресурсы API Gateway, управляемые CloudFormation. Это означает, что любые клиенты, использующие ваше WebSocket-приложение, должны будут перенаправлены, или необходимо будет установить другие DNS, чтобы облегчить переход.

Я рекомендую вам ознакомиться с моей оригинальной статьей для базового понимания того, как WebSockets работает на техническом уровне через соединения и обратные вызовы к API управления соединениями Amazon API Gateway.

Итак, поиграйте с нашими новыми подарками!

Как это работает — мы сохранили это знакомым

Интеграция WebSocket API в ваше бессерверное приложение будет казаться второй натурой, если вы уже используете наши http-события.

Простое приложение может выглядеть примерно так: serverless.yml:

Чтобы начать работу с нуля, вам нужно создать свой serverless-проект: sls create —template aws-nodejs. Перейдите к npm install —save serverless-websockets-plugin, а затем добавьте плагин в список плагинов serverless.yml:

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

Мир «hello world» приложений WebSocket

Ни один выпуск чего-либо, использующего WebSockets, не был бы полным без примера приложения, поэтому мы его создали. И так получилось, что это было массово масштабируемое, бессерверное приложение для чата.

Мы используем всех подозреваемых: API Gateway WebSockets (конечно же), AWS Lambda, DynamoDB и — возможно, самый интересный фрагмент всего этого — мы поговорим о потоках DynamoDB.

Архитектура чат-приложения

Когда пользователи подключаются и отключаются, мы сохраняем их идентификатор подключения в таблице DynamoDB, а также регистрируем их в канале чата «Общий».

Затем пользователи могут:

  • Подписаться на канал (первая подписка создает канал)

  • Отписаться от канала

  • отправить сообщение всем пользователям в канале.

Каждый раз, когда происходит одно из этих действий, мы отправляем сообщение всем подписчикам канала о том, что произошло. Если кто-то присоединился к каналу, покинул его (или отсоединился и покинул все каналы), или было отправлено сообщение.

Когда пользователь отсоединяется, мы используем сообщение «disconnect» от API Gateway для удаления всех подписок на соединения, чтобы не тратить циклы на отправку сообщений на мертвые соединения.

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

Почему именно потоки DynamoDB?

Итак, для чего мы используем потоки DynamoDB, спросите вы?

Чтобы продемонстрировать возможности этой архитектуры, мы решили подумать немного по-другому. Когда пользователь отписывается или подписывается на канал, мы не уведомляем всех сразу в одном вызове Lambda. Скорее, мы поручаем AWS Lambda получить этот поток и обработать его асинхронно.

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

Настоящая сила этого подхода заключается в следующем: допустим, у вас есть подслужбы или системы, которые хотят отправлять сообщения или запрещать пользователей. Этим подсистемам не нужно заботиться о реализации системы WebSocket; они просто работают с таблицей DynamoDB и могут создавать, обновлять и удалять подписки, отправлять сообщения ботам и т. д. Эти изменения происходят точно по такой же схеме, как если бы они были сделаны через WebSocket-клиентов.

Я думаю, что это довольно интересная концепция, и мне интересно посмотреть, что люди построят с ее помощью!

Несколько замечаний о WebSockets и ApiGatewayManagementApi

Вы не можете отправлять сообщения обратно типичным способом в виде полезной нагрузки HTTP-ответа, к которому вы привыкли в API Gateway HTTP. Просто верните свойство statusCode (например: 200) в полезной нагрузке, чтобы сообщить API Gateway, что все хорошо, но он не будет отправлять это клиенту. Если есть ошибки, например 500, они будут отправлены клиенту.

Вы не можете отправить сообщение WebSocket через Management API в маршруте $connect, которое должно быть успешным, прежде чем соединение сокета позволит передавать сообщения. Вы получите код 410, означающий, что соединение «Исчезло» (или еще не существует).

Для некоторого псевдокода это будет выглядеть примерно так:

Код ошибки 410 означает, что соединение пропало (или еще не установлено). В зависимости от вашего случая использования, вы можете захотеть очистить их в вашем хранилище данных, чтобы не продолжать попытки отправки сообщений!

Вы можете закрывать соединения со стороны «сервера» через ApiGatewayManagementApi. Кроме того, вызов маршрута $disconnect — это лучшая попытка, а не гарантия. (Тем не менее, я еще не видел, чтобы он не сработал, так что это похоже на небольшой крайний случай).

Если вы используете AWS CLI для отправки сообщений, обязательно используйте параметр —endpoint, чтобы переопределить используемый по умолчанию api на ваш фактический конечный пункт wss api. В документации это упоминается в описании команды на верхнем уровне, но не в описании после соединения.

Ознакомьтесь с документацией по ApiGatewayManagementApi для AWS NodeJS SDK и Boto3, чтобы узнать больше.

А теперь попробуйте!

Вы можете найти весь код на GitHub и запустить этот пример приложения для чата в своем собственном аккаунте AWS с помощью одного бессерверного развертывания.

А теперь отправляйтесь туда и создайте что-то замечательное!

Ресурсы

  • Полный пример приложения для чата на GitHub

  • Объяснение: Приложения реального времени с API Gateway WebSockets

Первоначально опубликовано на https://www.serverless.com.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *