Лучшие практики, которые я хотел бы знать при интеграции Stripe Webhooks

Лучшие практики, которые я хотел бы знать при интеграции Stripe Webhooks

12 января 2023 г.

Одним из преимуществ нашего продукта является интеграция Stripe без кода. При интеграции со Stigg мы берем на себя все, что связано с взаимодействием с Stripe для наших клиентов. Мы синхронизируем все планы и надстройки, клиентов и подписки, управляем состоянием этих объектов в Stigg и при необходимости распространяем изменения в Stripe. Мы также прослушиваем веб-перехватчики от Stripe, которые указывают на то, что что-то изменилось в синхронизированных объектах на стороне Stripe.

Одним из наиболее важных потоков в Stigg является поток создания подписки. При интеграции Stripe и создании платной подписки мы ждем входящего веб-перехватчика от Stripe, чтобы подтвердить, что платеж был успешно произведен, чтобы сделать подписку активной. Если подписка не будет создана по какой-либо причине, наши клиенты могут потерять деньги, поэтому она должна быть проверенной, надежной и легко масштабируемой.

В этой статье мы опишем лучшие практики создания интеграции веб-хука с Stripe. Мы сосредоточимся только на одной стороне нашей двусторонней интеграции: стороне, которая прослушивает веб-перехватчики и действует на них.

В чем проблема с запуском API для прослушивания веб-перехватчиков Stripe и обработки их?

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

Это может быть что-то вроде этого:

Для нас это было отлично для проверки концепции, но недостаточно хорошо, чтобы перейти к практической работе.

В этом дизайне есть несколько проблем, которые мы в команде инженеров заметили и хотели решить, чтобы быть уверенными в этой новой части интеграции:

* Что произойдет, если мы не работаем и веб-перехватчики не обрабатываются? * Что произойдет, если наша обработка завершится неудачно? * Как мы можем правильно отслеживать сбои? * Как мы можем быть уверены, что сможем самостоятельно повторно обработать неудачные события, если исправим потенциальную ошибку на нашей стороне?

Если Stripe бомбардирует нас событиями, как нам увеличить скорость обработки без потери данных? Чтобы ответить на эти вопросы, нам пришлось создать нечто иное. И со сложностью дизайна мы обнаружили, что есть много предостережений в том, как Stripe реализует свои веб-хуки. Некоторые из этих ограничений мы обнаружили с трудом, поэтому чтение этой статьи может избавить вас от многих усилий, связанных с интеграцией веб-перехватчиков.

Итак, вот несколько ограничений, которые мы должны были принять во внимание при разработке нового решения для надежной обработки веб-перехватчиков Stripe, и что это значит для нас:

* «Stripe не гарантирует доставку событий в том порядке, в котором они создаются» ~Stripe docs . Это означает, что нам нужно быть очень осторожными при обработке события, и мы не можем полагаться на то, что событие customer.subscription.created прибудет раньше, чем событие customer.subscription.updated. . Здорово, что мы можем обрабатывать параллельно столько, сколько захотим. Но на самом деле это не здорово, когда мы хотим сначала создать подписку, а затем обновить ее, как это происходит естественным образом.

* «Конечные точки веб-перехватчика могут иногда получать одно и то же событие более одного раза» ~Stripe docs . Это хороший. Все, что вы создаете, опираясь на веб-хук Stripe, должно быть Idempotence. Не пропустите!

* Вы не можете сохранить веб-перехватчик и повторно обработать его позже. Stripe ограничивает нас проверкой подписи веб-перехватчика в течение 5 минут, чтобы избежать воспроизведение атак. Если этого не сделать, событие завершится с ошибкой. Хотя это повышает безопасность, это не позволяет нам предлагать дизайн, в котором мы сохраняем все веб-хуки и обрабатываем их позже. Это невозможно, потому что первым шагом обработки веб-перехватчика является его распаковка с помощью stripe.webhooks.constructEvent, который проверяет подпись и завершится ошибкой, если будет вызван более чем через 5 минут после прибытия веб-перехватчика.

* «Stripe попытается уведомить вас о неправильно настроенной конечной точке по электронной почте, если конечная точка не отвечает кодом состояния HTTP 2xx в течение нескольких дней подряд» ~Документы Stripe. Если веб-перехватчики начинают давать сбой, не полагайтесь на Stripe, чтобы сообщить вам о проблеме. Через несколько дней вам сообщат, что что-то не так.

<цитата>

Мы учитываем все ограничения Stripes и наши требования как на уровне приложения кода, так и в том, как мы строим нашу архитектуру. ‍

Как смягчить ограничения 1 и 2?

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

Ограничение 1: Stripe не гарантирует доставку событий в том порядке, в котором они создаются

Это очень интересная тема, которая доставила нам немало хлопот в самом начале, когда мы только начинали. Для нас ключевым моментом было прослушивание правильных событий для различных вариантов использования и извлечение данных из Stripe в случае их отсутствия. Давайте рассмотрим конкретный пример. При создании подписки мы прослушиваем событие subscribe.created, чтобы активировать подписку после успешной оплаты. Мы также прослушиваем веб-хук для подписки.updated, чтобы синхронизировать статус подписки. В некоторых случаях, когда мы только начинали, мы получали события subscribe.updated перед событиями subscribe.created (именно так, как обещает документация Stripe). Это приводило к тому, что наша лямбда начинала генерировать исключения, когда веб-хуки поступали в неправильном порядке. Дескриптор «subscription.updated» ожидал, что мы уже обработали веб-перехватчик «subscription.created» и создали подписку.

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

Link to code

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

Ограничение 2: конечные точки веб-перехватчика могут иногда получать одно и то же событие более одного раза.

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

<цитата>

Последние два ограничения смягчаются на уровне инфраструктуры, поэтому давайте попробуем лучше понять, как спроектировать интеграцию веб-перехватчиков Stripe. ‍

Обзор:

  1. Шлюз AWS API, чтобы принять удар от Stripe.
  2. Лямбда-функция интеграции со шлюзом, которая проверяет подпись веб-перехватчиков и сохраняет их в очереди.
  3. AWS SQS с DLQ для повторной обработки.
  4. Функция AWS Lambda, которая будет считывать и обрабатывать событие.

А теперь давайте рассмотрим каждый элемент инфраструктуры и объясним, как он отвечает всем нашим техническим требованиям.

  1. Шлюз AWS API, чтобы принять удар от Stripe. (ограничение 3)

Нашим требованием здесь было создать API для получения веб-перехватчиков от Stripe и сохранения их в очереди без дополнительной логики, которая может стать точкой отказа и позже обработать их с помощью функции Lambda.

Мы знали, что API Gateway имеет встроенную интеграцию с SQS (и Lambda).

Нам этого было бы недостаточно, так как нам нужен был код, проверяющий и формирующий сообщения в момент их синхронного поступления (ограничение № 3).

В нашей реализации нам пришлось извлекать подпись Stripe из заголовков, чтобы использовать ее для проверки подлинности события и самого события Stripe. Мы достигли этого, используя шаблон сопоставления в запросе на интеграцию. По сути, это позволяет нам переназначить свойства HTTP-запросов на JSON, который будет легко обрабатываться лямбдой. В нашем случае мы сопоставляем Stripe Signature из заголовка webhook с параметром stripeSignature, а тело webhook — с параметром stripeEvent. Код сопоставления:

Link to code

  1. Лямбда-функция Интеграция со шлюзом (ограничение № 4)

В итоге мы выбрали встроенную интеграцию API Gateway Lambda, которая была бы очень простой и выполняла бы как можно меньше операций. Это важно для нас, так как это первый компонент, на который обращает внимание внешний веб-хук Stripe при входе в наше облако. Если не сохранить событие здесь, это приведет к невозможности обработки этого веб-перехватчика, и его данные будут потеряны навсегда.

Этот код сопоставления должен быть размещен на шлюзе API в запросах на интеграцию:

Link to code

Кроме того, мы очень тщательно отслеживаем эту лямбду на предмет ошибок, чтобы сразу же узнавать об упущенных веб-перехватчиках. Согласно ограничению № 4, Stripe потребуется несколько дней, чтобы сообщить нам о проблеме с вебхуками. Поскольку веб-перехватчики Stripe очень важны для нашего бизнеса, мы не можем позволить себе не знать, что с ними что-то не так, всего через несколько дней.

  1. AWS SQS с DLQ для повторной обработки

Мы уже в значительной степени полагаемся на Stigg, развернув SQS с DLQ, чтобы помочь нам быстро масштабироваться и обрабатывать несколько лямбда-выражений, когда это необходимо. Мы также полагаемся на эту архитектуру, чтобы автоматически повторять или вручную повторно обрабатывать сообщения, которые не удалось выполнить после устранения проблемы, вызвавшей сбой.

:::информация Также опубликовано здесь. р>

:::


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE