Skip to content

Commit

Permalink
Rebuild into async only with sync API
Browse files Browse the repository at this point in the history
Non-Breaking Changes:
* Merged clients into one
* Marked `Client` and `Channel` `final` through doc block and introduced interfaces for them for unit testing
* Dropped build in event loop, socket, and stream handling switching to [`react/event-loop`](https://reactphp.org/event-loop/), [`react/socket`](https://reactphp.org/socket/), and [`react/stream`](https://reactphp.org/stream/) for that
* Partially introduced strict typing and (return) type hints due to all the changes in the code
* Updated certain generated traits into generated classes
* Ensured performance didn't regress with these changes
* Updated all examples, tutorials, and the benchmark. Dropping the async variants due to the merge

Breaking changes:
* Raised minimum PHP version to 8.1+ unlocking the use of fibers
* Swapped [`react/promise`](https://reactphp.org/promise/) v2 with v3
* Dropped Event Loop injection and replaced it with the global loop accessor
```diff
<?php

-use Bunny\Async\Client;
+use Bunny\Client;
-use React\EventLoop\Factory;

require dirname(__DIR__, 2) . '/vendor/autoload.php';

-$loop = Factory::create();

-(new Client($loop))->connect();
+$client = new Client();

-$loop->run();
```

* Merged `Async` and `Sync` clients into `Client` utilizing fibers through [`react/async`](https://reactphp.org/async/)

`receive.php`:
```diff
<?php

use Bunny\Channel;
use Bunny\Client;
use Bunny\Message;

require dirname(__DIR__, 2) . '/vendor/autoload.php';

-$client = (new Client())->connect();
+$client = new Client();
$channel = $client->channel();

$channel->queueDeclare('hello', false, false, false, false);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

-$channel->run(
+$channel->consume(
    function (Message $message, Channel $channel) {
        echo " [x] Received ", $message->content, "\n";
    },
    'hello',
    '',
    false,
    true,
);
```

`send.php`:
```diff
<?php

use Bunny\Client;

require dirname(__DIR__, 2) . '/vendor/autoload.php';

-$client = (new Client())->connect();
+$client = new Client();
$channel = $client->channel();
$channel->queueDeclare('hello', false, false, false, false);
$channel->close();

$channel->publish('Hello World!', [], '', 'hello');
echo " [x] Sent 'Hello World!'\n";

$channel->close();
$client->disconnect();
```

`receive-async.php`:
```diff
<?php

use Bunny\Channel;
-use Bunny\Async\Client;
+use Bunny\Client;
use Bunny\Message;
-use React\EventLoop\Factory;

require dirname(__DIR__, 2) . '/vendor/autoload.php';

-$loop = Factory::create();

-(new Client($loop))->connect()
+$client = new Client();
-->then(function (Client $client) {
-    return $client->channel();
-})
+$channel = $client->channel();

-->then(function (Channel $channel) {
-    return $channel->queueDeclare('hello', false, false, false, false)->then(function () use ($channel) {
-        return $channel;
-    });
-})
+$channel->queueDeclare('hello', false, false, false, false);

-->then(function (Channel $channel) {
-    echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
-    $channel->consume(
-        function (Message $message, Channel $channel, Client $client) {
-            echo " [x] Received ", $message->content, "\n";
-        },
-        'hello',
-        '',
-        false,
-        true
-    );
-});
+echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

+$channel->consume(
+    function (Message $message, Channel $channel) {
+        echo " [x] Received ", $message->content, "\n";
+    },
+    'hello',
+    '',
+    false,
+    true,
+);

-$loop->run();
```

`send-async.php`:
```diff
<?php

-use Bunny\Channel;
-use Bunny\Async\Client;
+use Bunny\Client;
-use React\EventLoop\Factory;

require dirname(__DIR__, 2) . '/vendor/autoload.php';

-$loop = Factory::create();

-(new Client($loop))->connect()
+$client = new Client();

-->then(function (Client $client) {
-    return $client->channel();
-})
+$channel = $client->channel();

-->then(function (Channel $channel) {
-    return $channel->queueDeclare('hello', false, false, false, false)->then(function () use ($channel) {
-        return $channel;
-    });
-})
+$channel->queueDeclare('hello', false, false, false, false);

-->then(function (Channel $channel) {
-    echo " [x] Sending 'Hello World!'\n";
-    return $channel->publish('Hello World!', [], '', 'hello')->then(function () use ($channel) {
-        return $channel;
-    });
-})
+$channel->publish('Hello World!', [], '', 'hello');

-->then(function (Channel $channel) {
-    echo " [x] Sent 'Hello World!'\n";
-    $client = $channel->getClient();
-    return $channel->close()->then(function () use ($client) {
-        return $client;
-    });
-})
+echo " [x] Sent 'Hello World!'\n";
+$channel->close();

-->then(function (Client $client) {
-    $client->disconnect();
-});
+$client->disconnect();
```

* Channel::queueBind arguments `string $queue` and `string $exchange` switched argument locations
```diff
<?php

use Bunny\Channel;
use Bunny\Client;
use Bunny\Message;

require dirname(__DIR__, 2) . '/vendor/autoload.php';

$client = new Client();
$channel = $client->channel();

$channel->exchangeDeclare('logs', 'fanout');
$queue = $channel->queueDeclare('', false, false, true, false);
-$channel->queueBind($queue->queue, 'logs');
+$channel->queueBind('logs', $queue->queue);
```
  • Loading branch information
WyriHaximus committed May 10, 2024
1 parent 464507a commit b295581
Show file tree
Hide file tree
Showing 144 changed files with 3,559 additions and 6,285 deletions.
21 changes: 1 addition & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,26 +193,7 @@ $channel->qos(

### Asynchronous usage

Bunny supports both synchronous and asynchronous usage utilizing [ReactPHP](https://github.com/reactphp). The following example shows setting up a client and consuming a queue indefinitely.

```php
(new Async\Client($eventLoop, $options))->connect()->then(function (Async\Client $client) {
return $client->channel();
})->then(function (Channel $channel) {
return $channel->qos(0, 5)->then(function () use ($channel) {
return $channel;
});
})->then(function (Channel $channel) use ($event) {
$channel->consume(
function (Message $message, Channel $channel, Async\Client $client) use ($event) {
// Handle message

$channel->ack($message);
},
'queue_name'
);
});
```
**Node: Up to version `v0.5.x` Bunny had two different clients, one sync, and one async. As of `v0.6` both clients have been folder into one: An async client with a sync API.**

## AMQP interop

Expand Down
10 changes: 5 additions & 5 deletions benchmark/consumer.php
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
<?php
namespace Bunny;

use Bunny\Message;

require_once __DIR__ . "/../vendor/autoload.php";

$c = new Client();
$ch = $c->connect()->channel();

$ch->queueDeclare("bench_queue");
$ch->exchangeDeclare("bench_exchange");
$ch->queueBind("bench_queue", "bench_exchange");
$ch->queueBind("bench_exchange", "bench_queue");

$t = null;
$count = 0;

$ch->run(function (Message $msg, Channel $ch, Client $c) use (&$t, &$count) {
$ch->consume(function (Message $msg, Channel $ch, Client $c) use (&$t, &$count) {
if ($t === null) {
$t = microtime(true);
}

if ($msg->content === "quit") {
printf("Pid: %s, Count: %s, Time: %.4f\n", getmypid(), $count, microtime(true) - $t);
$c->stop();
$c->disconnect();
} else {
++$count;
}

}, "bench_queue", "", false, true);

$c->disconnect();
46 changes: 0 additions & 46 deletions benchmark/consumer_async.php

This file was deleted.

4 changes: 3 additions & 1 deletion benchmark/producer.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php
namespace Bunny;

use Bunny\Client;

require_once __DIR__ . "/../vendor/autoload.php";

$c = new Client();
Expand All @@ -9,7 +11,7 @@

$ch->queueDeclare("bench_queue");
$ch->exchangeDeclare("bench_exchange");
$ch->queueBind("bench_queue", "bench_exchange");
$ch->queueBind("bench_exchange", "bench_queue");

$body = <<<EOT
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
Expand Down
60 changes: 0 additions & 60 deletions benchmark/producer_async.php

This file was deleted.

34 changes: 20 additions & 14 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "bunny/bunny",
"type": "library",
"description": "Performant pure-PHP AMQP (RabbitMQ) sync/async (ReactPHP) library",
"description": "Performant pure-PHP AMQP (RabbitMQ) non-blocking ReactPHP library",
"keywords": [
"rabbitmq",
"rabbit",
Expand All @@ -14,7 +14,10 @@
"exchange",
"react",
"react-php",
"reactphp"
"reactphp",
"async",
"await",
"fibers"
],
"minimum-stability": "stable",
"license": "MIT",
Expand All @@ -25,29 +28,32 @@
}
],
"require": {
"php": "^7.1 || ^8.0",
"react/event-loop": "^1.0 || ^0.5 || ^0.4",
"react/promise": "~2.2"
"php": "^8.1",
"react/event-loop": "^1.5",
"react/promise": "^3.1",
"react/stream": "^1.3",
"react/async": "^4.2",
"react/socket": "^1.15",
"react/promise-timer": "^1.10",
"evenement/evenement": "^3",
"react/promise-stream": "^1.7"
},
"require-dev": {
"ext-pcntl": "*",
"phpunit/phpunit": "^9.5 || ^7.5.20",
"symfony/process": "^6.1 || ^4.4",
"phpstan/phpstan": "^1.10"
},
"suggest": {
"ext-pcntl": "For using synchronous AMQP/RabbitMQ client"
"phpunit/phpunit": "^9.6",
"phpstan/phpstan": "^1.10",
"react/child-process": "^0.6.5",
"wyrihaximus/react-phpunit-run-tests-in-fiber": "^2 || ^1"
},
"autoload": {
"psr-4": {
"Bunny\\": "src/Bunny/"
"Bunny\\": "src/"
}
},
"autoload-dev": {
"files": ["test/Library/functions.php"],
"psr-4": {
"Bunny\\": "test/Bunny/",
"Bunny\\Test\\Library\\": "test/Library/"
"Bunny\\Test\\": "test/"
}
}
}
91 changes: 0 additions & 91 deletions examples/worker-async.php

This file was deleted.

Loading

0 comments on commit b295581

Please sign in to comment.