Skip to content

feat: add Messenger class for multiple adapter failover support#128

Open
deepshekhardas wants to merge 1 commit into
utopia-php:mainfrom
deepshekhardas:fix/115-messenger-failover
Open

feat: add Messenger class for multiple adapter failover support#128
deepshekhardas wants to merge 1 commit into
utopia-php:mainfrom
deepshekhardas:fix/115-messenger-failover

Conversation

@deepshekhardas

Copy link
Copy Markdown

Port of PR #115 by TorstenDittmann.

Adds Messenger class that orchestrates multiple messaging adapters with automatic failover. If one adapter fails, it falls back to the next in the list.

Changes:

  • New Messenger class with failover orchestration
  • Adapter compatibility validation (same type/message type)
  • 14 comprehensive tests
  • Updated README with usage example

@greptile-apps

greptile-apps Bot commented Jun 14, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a Messenger class that wraps multiple messaging adapters and provides automatic exception-based failover, trying each adapter in sequence until one succeeds or all have failed.

  • Messenger.php: New orchestration class with constructor-time validation (empty list, non-adapter elements, mixed adapter/message types), a send() method with failover loop and aggregate error reporting, and helpers (getType, getMessageType, getMaxMessagesPerRequest).
  • MessengerTest.php: 14 tests covering success path, single/multi-adapter failover, all-fail aggregation, type validation, and the explicit design decision that non-exception failure payloads do not trigger fallback.
  • README.md: Usage example added for the Messenger with Twilio/Vonage failover scenario.

Confidence Score: 4/5

Safe to merge after confirming the open discussions from earlier review rounds are resolved; the core logic is sound but the failover mechanism has edge cases worth closing before shipping.

The implementation is well-structured and the test suite is thorough. However, the failover catch block covers only \Exception, meaning \Error subclasses thrown by adapters (e.g. \TypeError from a broken process() implementation) escape the loop and propagate immediately without trying subsequent adapters. That gap was raised in a prior round and remains unaddressed in the diff, leaving the failover guarantee incomplete for a real-world failure class that adapters can plausibly produce.

src/Utopia/Messaging/Messenger.php — the catch block and the soft-failure/getMaxMessagesPerRequest contract warrant a second look before merge.

Important Files Changed

Filename Overview
src/Utopia/Messaging/Messenger.php New Messenger class with failover orchestration; catch block uses \Exception instead of \Throwable, so \Error subclasses (e.g. \TypeError) bypass failover entirely
tests/Messaging/MessengerTest.php 14 well-structured tests covering success, failover, all-fail, type validation, and edge cases; no issues found
README.md Adds clear usage example for the new Messenger class with accurate description of failover behaviour

Reviews (2): Last reviewed commit: "feat: add Messenger class for multiple a..." | Re-trigger Greptile

Comment on lines +90 to +95
if (! \is_a($message, $messageType)) {
throw new \Exception(
'Invalid message type. Expected "'
.$messageType
.'", got "'
.\get_class($message)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Failover skipped on \Error subclasses

The catch block only catches \Exception, so any \TypeError or other \Error thrown by an adapter will propagate immediately without trying the next adapter, defeating the purpose of failover. Changing to \Throwable would cover both \Exception and \Error hierarchies.

Comment thread src/Utopia/Messaging/Messenger.php
Based on PR utopia-php#115 by TorstenDittmann. Adds Messenger class that orchestrates multiple adapters with automatic failover.
@deepshekhardas deepshekhardas force-pushed the fix/115-messenger-failover branch from d4b60e4 to 834d575 Compare June 17, 2026 09:14
* successful adapter.
*
* @param Message $message The message to send.
* @return array{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Soft-failure responses bypass failover silently

Messenger::send() only falls back on thrown exceptions, so an adapter that returns a response with deliveredTo: 0 and all-failure results is treated as "success" — the second adapter is never tried. This is documented by the test, but the behaviour may surprise callers who expect the Messenger to be smarter about delivery failures. At minimum, the PHPDoc and README should warn that "failure" payloads without an exception are returned as-is without attempting the next adapter, so callers must inspect deliveredTo themselves.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant