Skip to content

feat: amqp swoole #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

feat: amqp swoole #47

wants to merge 1 commit into from

Conversation

loks0n
Copy link

@loks0n loks0n commented Jun 13, 2025

Summary by CodeRabbit

  • New Features

    • Introduced support for Swoole-based AMQP connections, providing automatic channel reconnection and retry on failure.
  • Chores

    • Updated dependencies to use a custom AMQP package from a specified repository.

Copy link

coderabbitai bot commented Jun 13, 2025

Walkthrough

The changes introduce a new AMQPSwoole class extending AMQP, providing a custom channel management and retry mechanism using AMQPSwooleConnection. The AMQP class is refactored to use protected visibility for several properties and methods, enabling subclass extension. The composer.json is updated to use a custom fork of the AMQP library from a specific Git repository.

Changes

File(s) Change Summary
composer.json Switched AMQP dependency to custom fork and added VCS repository configuration.
src/Queue/Broker/AMQP.php Changed class property and constructor parameter visibilities from private to protected; changed withChannel method visibility from private to protected.
src/Queue/Broker/AMQPSwoole.php Added new AMQPSwoole class with overridden protected withChannel method implementing retry logic on channel failure.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant AMQPSwoole
    participant AMQPSwooleConnection
    participant AMQPChannel

    Caller->>AMQPSwoole: withChannel(callback)
    alt Channel exists
        AMQPSwoole->>AMQPChannel: Use existing channel
    else Channel does not exist
        AMQPSwoole->>AMQPSwooleConnection: Create new connection
        AMQPSwooleConnection->>AMQPChannel: Create new channel
        AMQPSwoole->>AMQPChannel: Store and use new channel
    end
    AMQPSwoole->>Caller: Execute callback(channel)
    alt Exception occurs
        AMQPSwoole->>AMQPChannel: Reset channel
        AMQPSwoole->>AMQPSwooleConnection: Create new connection
        AMQPSwooleConnection->>AMQPChannel: Create new channel
        AMQPSwoole->>Caller: Retry callback(channel)
    end
Loading

Poem

In the warren of code, a new tunnel appears,
AMQPSwoole hops in, dispelling old fears.
With channels that retry, and connections anew,
Protected fields open for subclasses too!
Composer’s map points to a custom trail—
Rabbit devs rejoice, thump-thump their tails! 🐇


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0d1531 and 3a58ba2.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • composer.json (2 hunks)
  • src/Queue/Broker/AMQP.php (2 hunks)
  • src/Queue/Broker/AMQPSwoole.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • composer.json
  • src/Queue/Broker/AMQPSwoole.php
  • src/Queue/Broker/AMQP.php
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Adapter Tests (AMQP)
  • GitHub Check: Adapter Tests (SwooleRedisCluster)
  • GitHub Check: Adapter Tests (Swoole)
  • GitHub Check: Adapter Tests (Pool)
  • GitHub Check: Adapter Tests (Workerman)
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
composer.json (1)

26-31: Prefer HTTPS over SSH for public composer repositories

Using an ssh:// style URL ([email protected]:…) forces every consumer (including CI runners) to have SSH keys configured.
Switching to HTTPS (https://github.com/appwrite-labs/php-amqplib.git) makes the package consumable out-of-the-box and avoids flaky builds when the SSH agent isn’t available.

-        "url": "[email protected]:appwrite-labs/php-amqplib.git"
+        "url": "https://github.com/appwrite-labs/php-amqplib.git"
src/Queue/Broker/AMQPSwoole.php (1)

16-35: Channel factory duplicates parent logic – introduce a shared helper

$createChannel is copy-pasted from the parent class with only the connection class changed. This violates DRY and risks diverging behaviour.

Possible directions:

  1. Move the factory into a protected createConnection(): AbstractConnection in the parent and only override that.
  2. Accept a callable $connectionFactory via constructor.

Keeps reconnection flow in one place and simplifies future fixes.

src/Queue/Broker/AMQP.php (2)

22-26: Visibility relaxed – ensure invariants are documented

Exposing $exchangeArguments, $queueArguments, … as protected empowers subclasses but removes encapsulation guarantees.
Add PHPDoc notes describing the expected shapes (array<string,string> etc.) and whether mutation after initialisation is allowed.


185-221: withChannel logic duplicated in subclass – candidate for Template Method

Given the near-identical method in AMQPSwoole, extract the common reconnect wrapper into the parent and delegate only connection creation to a small overridable hook (protected function createChannel(): AMQPChannel). Reduces maintenance overhead.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 498bbbe and b0d1531.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • composer.json (1 hunks)
  • src/Queue/Broker/AMQP.php (2 hunks)
  • src/Queue/Broker/AMQPSwoole.php (1 hunks)
🔇 Additional comments (1)
src/Queue/Broker/AMQP.php (1)

38-47: Constructor parameters made readonly – 👍

Switching to readonly ensures connection details remain immutable after construction, preventing subtle race conditions when objects are reused.

Comment on lines 32 to 35
"require": {
"php": ">=8.3",
"php-amqplib/php-amqplib": "^3.7",
"appwrite-labs/php-amqplib": "master-dev",
"utopia-php/cli": "0.15.*",
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Unpinned “master-dev” constraint is brittle

"appwrite-labs/php-amqplib": "master-dev" points to a moving target. Any force-push on that branch can silently break downstream builds.

Pin to a tag or specific commit and optionally allow caret/tilde ranges for controlled updates:

-        "appwrite-labs/php-amqplib": "master-dev",
+        "appwrite-labs/php-amqplib": "1.0.0",        // or an exact commit hash

Follow-up: If no stable tag exists yet, consider adding "minimum-stability": "dev" with an explicit "prefer-stable": true to keep Composer satisfied.


🏁 Script executed:

#!/bin/bash
# Locate the php-amqplib entry and surrounding context
grep -R '"appwrite-labs/php-amqplib"' -n composer.json -A3 -B2

# Check for existing stability settings
grep -R '"minimum-stability"' -n composer.json
grep -R '"prefer-stable"' -n composer.json

Length of output: 424


Pin unstable dependency instead of tracking master-dev

Your composer.json is pulling a moving target for the AMQP library:

  • Location: composer.json (line 34)
  • Current requirement:
    "appwrite-labs/php-amqplib": "master-dev",

This can lead to silent breakages whenever that branch is force-pushed. Pin to a released version or exact commit:

- "appwrite-labs/php-amqplib": "master-dev",
+ "appwrite-labs/php-amqplib": "1.0.0",  // or "dev-master as 1.0.0" / specific commit hash

You already have

"minimum-stability": "stable"

so the -dev suffix on your requirement will still install the branch. No change to stability settings is required unless you intend to broadly allow dev-level packages—in which case add:

"minimum-stability": "dev",
"prefer-stable": true
🤖 Prompt for AI Agents
In composer.json around lines 32 to 35, the dependency
"appwrite-labs/php-amqplib" is set to "master-dev", which is a moving target and
can cause silent breakages. Replace "master-dev" with a specific released
version tag or an exact commit hash to pin the dependency. Since
"minimum-stability" is already set to "stable", no changes are needed there
unless you want to allow dev packages more broadly, in which case add
"minimum-stability": "dev" and "prefer-stable": true.

Comment on lines +37 to +40
if (!$this->channel) {
$this->channel = $createChannel();
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

$this->channel is shared across Swoole coroutines – risk of data races

With Swoole each coroutine can resume at any point; sharing a single AMQPChannel instance can lead to:

• Unexpected frame interleaving
• “Channel closed” exceptions when one coroutine finishes/acks while another consumes

Consider storing the channel in coroutine-local storage (Swoole\Coroutine::getCid() keyed array) or creating a new channel per withChannel invocation.

🤖 Prompt for AI Agents
In src/Queue/Broker/AMQPSwoole.php around lines 37 to 40, the current code
shares a single AMQPChannel instance across all Swoole coroutines, which can
cause data races and channel errors. To fix this, modify the code to either
store the channel in a coroutine-local storage keyed by
Swoole\Coroutine::getCid() or create a new AMQPChannel instance each time
withChannel is invoked, ensuring each coroutine uses its own separate channel
instance.

Comment on lines +41 to +49
try {
$callback($this->channel);
} catch (\Throwable) {
// createChannel() might throw, in that case set the channel to `null` first.
$this->channel = null;
// try creating a new connection once, if this still fails, throw the error
$this->channel = $createChannel();
$callback($this->channel);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

First exception is lost during reconnect – hampers debugging

The catch block discards the original Throwable. If the reconnection also fails, the second exception bubbles up and the root cause is gone.

Capture and chain:

-        } catch (\Throwable) {
+        } catch (\Throwable $first) {-            $this->channel = $createChannel();
-            $callback($this->channel);
+            try {
+                $this->channel = $createChannel();
+                $callback($this->channel);
+            } catch (\Throwable $second) {
+                $second->addPrevious($first); // or include it in a new RuntimeException
+                throw $second;
+            }
         }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/Queue/Broker/AMQPSwoole.php around lines 41 to 49, the catch block
discards the original Throwable, causing loss of the root cause if the
reconnection also fails. Modify the catch block to capture the first exception,
then if the reconnection fails, throw a new exception that chains or includes
the original one to preserve the root cause for debugging.

@loks0n loks0n force-pushed the feat-amqp-swoole branch from b0d1531 to 3a58ba2 Compare June 14, 2025 10:30
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