Хочу рассказать на ноябрьской встрече минут 15 про вебхуки от платёжной системы. История такая: платёжка прислала одно и то же уведомление три раза за 40 секунд, наш обработчик в Sidekiq дважды честно провёл платёж, клиенту на баланс упали деньги два раза, а потом неделю разбирались с бухгалтерией. Ничего экзотического, просто никто не принял всерьёз, что «доставка хотя бы один раз» значит ровно это. Покажу, как сделали: уникальный индекс на id события и запись события в той же транзакции, что и проводка.
class PaymentWebhookJob
include Sidekiq::Job
sidekiq_options retry: 10
def perform(event_id, payload)
ActiveRecord::Base.transaction do
WebhookEvent.create!(external_id: event_id, payload: payload)
Payments::Apply.call(payload)
end
rescue ActiveRecord::RecordNotUnique
Rails.logger.info("duplicate webhook #{event_id}")
end
end
Если проводка упала, транзакция откатится вместе с записью события и ретрай пройдёт заново. Отдельно расскажу, почему 25 ретраев по умолчанию для платежей опасны.
Ставлю тебя на 22 ноября первым слотом. Тема как раз для тех, кто думает, что у них такого не бывает
Интересно, сколько стоит этот уникальный индекс на вставке, если вебхуков тысячи в минуту. Принесёшь цифры? Я бы ещё сравнил с вариантом через SET NX в Redis, по задержке он наверняка быстрее, но там свои вопросы с TTL.
Приду. Покажи ещё, где держать payload: в jsonb или отдельными колонками, это всегда спрашивают
Цифры принесу, но они скучные: в пиках у нас около 2 тысяч событий в час, вставка с индексом на графиках не видна совсем. Payload храним в jsonb, всё старше 90 дней раз в неделю чистит отдельная джоба. Про Redis Егор ответил ровно то, что я сказала бы сама.