Вопрос или проблема
Итак, сценарий простой: я хочу настроить эмулятор pubsub от Google так, чтобы у него была тема для очереди мертвых писем, и если сообщение вызывает исключение в обработчике, это сообщение должно быть перенаправлено в тему очереди мертвых писем. Затем я хочу иметь возможность подписаться на эту тему и извлекать мертвые письма из нее. Я использую spring-cloud-gcp-starter-pubsub в моих продюсерах и потребителях, затем использую следующие команды оболочки, чтобы запустить и настроить эмулятор:
gcloud beta emulators pubsub start --project=local-test --host-port=0.0.0.0:8080
затем после того, как он полностью запустится,
curl -X PUT -v http://localhost:8080/v1/projects/local-test/topics/fam-task
curl -X PUT -v http://localhost:8080/v1/projects/local-test/topics/dead-letter
curl -X PUT 'http://localhost:8080/v1/projects/local-test/subscriptions/subscription-task-reactor-fam-task' \
--header 'Content-Type: application/json' --data '{"topic": "projects/local-test/topics/fam-task", "enableMessageOrdering": true, "enableExactlyOnceDelivery": true, "deadLetterPolicy": {"deadLetterTopic": "projects/local-test/topics/dead-letter", "maxDeliveryAttempts": 5}}'
echo "Создать подписки для мертвых писем"
curl -X PUT 'http://localhost:8080/v1/projects/local-test/subscriptions/subscription-dead-letter' \
--header 'Content-Type: application/json' --data '{"topic": "projects/local-test/topics/dead-letter", "enableMessageOrdering": true, "enableExactlyOnceDelivery": true}'
Мне удается проверить, что продюсеры и потребители правильно связаны между собой и отправляют/получают сообщения, как ожидалось. Для целей проверки концепции я заставляю метод получения просто выбрасывать новое RuntimeException() при получении сообщения. Когда это происходит, в логах моего приложения отображается
PubSubInboundChannelAdapter – Отправка сообщения Spring [4] не удалась; сообщение автоматически отклонено.
5 раз, что соответствует ожидаемому поведению, определенному при создании subscription-task-reactor-fam-task, но опрос очереди мертвых писем с помощью
POST http://localhost:8080/v1/projects/local-test/subscriptions/subscription-dead-letter:pull
приводит к тайм-ауту без возвращаемых сообщений. Подписка и тема существуют, тема мертвых писем существует и, кажется, задана при создании подписки. Подписка на тему мертвых писем существует, действительна и может быть опрошена, просто даже когда сообщения отклоняются, они не отображаются, когда я опрашиваю тему мертвых писем. Я вижу другие вопросы с ответами о том, чтобы убедиться, что у учетной записи службы есть доступные роли подписчика и издателя, но я не уверен, как (если вообще) это относится к эмулятору. Есть идеи, что я делаю не так?
Ответ или решение
Вопрос, с которым вы столкнулись, касается настройки "dead letter queue" (DLQ) в эмуляторе Pub/Sub от Google. Правильная конфигурация DLQ имеет решающее значение для управления отсечёнными сообщениями, которые не могут быть обработаны после нескольких попыток. Давайте проанализируем вашу ситуацию и выясним, почему сообщения, которые не были успешно обработаны, не поступают в заданный вами "dead letter topic".
1. Объяснение конфигурации
Вы уже создали два топика: fam-task
и dead-letter
, а также настройки подписки subscription-task-reactor-fam-task
. Это правильные шаги, однако давайте остановимся на важности правильной конфигурации политики мёртвых письем. В вашем случае:
"deadLetterPolicy": {
"deadLetterTopic": "projects/local-test/topics/dead-letter",
"maxDeliveryAttempts": 5
}
Эта конфигурация предполагает, что если сообщение не может быть обработано после пяти попыток, оно будет перенаправлено в указанный вами мёртвый топик. Однако есть несколько моментов, которые стоит проверить внимательнее.
2. Обработка исключений
Вы указали, что ваша обработка сообщения завершается с выбросом RuntimeException
. Важно убедиться, что ваш обработчик корректно ловит исключения и передаёт обратную связь о неудачных обработках в сервис Pub/Sub. Просто выбрасывание исключения не всегда приводит к "nack"-у сообщения. Убедитесь, что вы используете корректные механизмы для этой обработки. Например, в Spring нужно правильно настраивать уровень обработки ошибок и возможности обработки сообщений.
3. Качество сообщений и атрибуты
Проверьте, что все сообщения, которые вы отправляете в fam-task
, соответствуют требованиям Pub/Sub. Иногда дополнительные атрибуты, требуемые в сообщении, могут влиять на его доставку в DLQ. Убедитесь, что формат и содержимое сообщений корректны.
4. Особенности эмулятора
Локальный эмулятор Google Pub/Sub может вести себя несколько иначе, чем реальный сервис. Например, он может не полностью поддерживать все функции, доступные в облачном варианте. Убедитесь, что ваша версия эмулятора актуальна и поддерживает функции, которые вы хотите использовать, включая мёртвые темы и подписки.
5. Аутентификация и роли
Вы затронули аспекты аутентификации и ролей. В эмуляторе вам не потребуется настраивать роли для сервисных учётных записей, как это требуется в облаке. Все тесты можно проводить в рамках локальной среды, но убедитесь, что приложение правильно настроено для работы с эмулятором, и что у него есть необходимые разрешения для отправки запросов.
6. Временные задержки
Иногда сообщения могут не сразу появляться в DLQ. Возможны временные задержки или проблемы с сетью вызова, что может привести к тому, что результат /pull
не показывает ожидаемое поведение. Попробуйте добавить небольшую паузу между попытками получения сообщений из мёртвого топика.
Заключение
Для того чтобы решить проблему с не поступающими мёртвыми сообщениями в вашем случае, вам нужно тщательно проверить порядок обработки исключений, алиасы и форматы сообщений, а также провести дополнительные тесты с учётом особенностей эмулятора. Если после выполнения всех этих шагов проблема сохраняется, рекомендуется обратиться к официальной документации Google Pub/Sub и, возможно, в сообщество разработчиков для получения более целенаправленной помощи.