Skip to content

Commit

Permalink
Merge branch 'master' into simplify-envelopes
Browse files Browse the repository at this point in the history
  • Loading branch information
viktorprogger authored Oct 13, 2024
2 parents 3afb619 + f857522 commit e297466
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 5 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/bechmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
on:
pull_request:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'
- 'infection.json.dist'
- 'psalm.xml'
- 'tests/**'

push:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'
- 'infection.json.dist'
- 'psalm.xml'
- 'tests/**'

name: bechmark

jobs:
phpbench:
uses: yiisoft/actions/.github/workflows/phpbench.yml@master
with:
os: >-
['ubuntu-latest', 'windows-latest']
php: >-
['8.1']
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
},
"require-dev": {
"maglnet/composer-require-checker": "^4.7",
"phpbench/phpbench": "^1.3",
"phpunit/phpunit": "^10.5",
"rector/rector": "^1.0.0",
"roave/infection-static-analysis-plugin": "^1.34",
Expand Down
8 changes: 8 additions & 0 deletions phpbench.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema":"./vendor/phpbench/phpbench/phpbench.schema.json",
"runner.bootstrap": "vendor/autoload.php",
"runner.path": "tests/Benchmark",
"runner.revs": 100000,
"runner.iterations": 5,
"runner.warmup": 5
}
109 changes: 109 additions & 0 deletions tests/Benchmark/MetadataBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\Benchmark;

use Generator;
use PhpBench\Attributes\ParamProviders;
use PhpBench\Model\Tag;
use Yiisoft\Queue\Message\IdEnvelope;
use Yiisoft\Queue\Message\Message;
use Yiisoft\Queue\Message\MessageInterface;
use Yiisoft\Queue\Middleware\FailureHandling\FailureEnvelope;

final class MetadataBench
{
/**
* Create metadata as array and read its value from array
*/
#[Tag('metadata_read')]
public function benchArrayRead(): void
{
$message = new Message('foo', 'bar', ['id' => 1]);
$id = $message->getMetadata()['id'];
}

/**
* Create metadata as object and read its value immediately
*/
#[Tag('metadata_read')]
public function benchEnvelopeRead(): void
{
$message = new IdEnvelope(new Message('foo', 'bar'), 1);
$id = $message->getId();
}

/**
* Create metadata as array and read its value from an envelope object
*/
#[Tag('metadata_read')]
public function benchEnvelopeReadRestored(): void
{
$message = IdEnvelope::fromMessage(new Message('foo', 'bar', ['id' => 1]));
$id = $message->getId();
}

public function provideEnvelopeStack(): Generator
{
$config = [1 => 'one', 5 => 'three', 15 => 'fifteen'];
$message = new IdEnvelope(new Message('foo', 'bar'), 1);

for ($i = 1; $i <= max(...array_keys($config)); $i++) {
$message = new FailureEnvelope($message, ["fail$i" => "fail$i"]);
if (isset($config[$i])) {
yield $config[$i] => ['message' => $message];
}
}
}

/**
* Read metadata value from an envelope object restored from an envelope stacks of different depth
*
* @psalm-param array{message: MessageInterface} $params
*/
#[ParamProviders('provideEnvelopeStack')]
#[Tag('metadata_read')]
public function benchEnvelopeReadFromStack(array $params): void
{
$id = IdEnvelope::fromMessage($params['message'])->getId();
}

public function provideEnvelopeStackCounts(): Generator
{
yield 'one' => [1];
yield 'three' => [3];
yield 'fifteen' => [15];
}

/**
* Create envelope stack with the given depth
*
* @psalm-param array{0: int} $params
*/
#[ParamProviders('provideEnvelopeStackCounts')]
#[Tag('metadata_create')]
public function benchEnvelopeStackCreation(array $params): void
{
$message = new Message('foo', 'bar');
for ($i = 0; $i < $params[0]; $i++) {
$message = new FailureEnvelope($message, ["fail$i" => "fail$i"]);
}
}

/**
* Create metadata array with the given elements count
*
* @psalm-param array{0: int} $params
*/
#[ParamProviders('provideEnvelopeStackCounts')]
#[Tag('metadata_create')]
public function benchMetadataArrayCreation(array $params): void
{
$metadata = ['failure-meta' => []];
for ($i = 0; $i < $params[0]; $i++) {
$metadata['failure-meta']["fail$i"] = "fail$i";
}
$message = new Message('foo', 'bar', $metadata);
}
}
112 changes: 112 additions & 0 deletions tests/Benchmark/QueueBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\Benchmark;

use Generator;
use PhpBench\Attributes\ParamProviders;
use PhpBench\Model\Tag;
use Psr\Log\NullLogger;
use Yiisoft\Injector\Injector;
use Yiisoft\Queue\Cli\SimpleLoop;
use Yiisoft\Queue\Message\IdEnvelope;
use Yiisoft\Queue\Message\JsonMessageSerializer;
use Yiisoft\Queue\Message\Message;
use Yiisoft\Queue\Middleware\CallableFactory;
use Yiisoft\Queue\Middleware\Consume\ConsumeMiddlewareDispatcher;
use Yiisoft\Queue\Middleware\Consume\MiddlewareFactoryConsume;
use Yiisoft\Queue\Middleware\FailureHandling\FailureEnvelope;
use Yiisoft\Queue\Middleware\FailureHandling\FailureMiddlewareDispatcher;
use Yiisoft\Queue\Middleware\FailureHandling\MiddlewareFactoryFailure;
use Yiisoft\Queue\Middleware\Push\MiddlewareFactoryPush;
use Yiisoft\Queue\Middleware\Push\PushMiddlewareDispatcher;
use Yiisoft\Queue\Queue;
use Yiisoft\Queue\QueueInterface;
use Yiisoft\Queue\Tests\Benchmark\Support\VoidAdapter;
use Yiisoft\Queue\Worker\Worker;
use Yiisoft\Test\Support\Container\SimpleContainer;

final class QueueBench
{
private readonly QueueInterface $queue;
private readonly JsonMessageSerializer $serializer;
private readonly VoidAdapter $adapter;

public function __construct()
{
$container = new SimpleContainer();
$callableFactory = new CallableFactory($container);
$logger = new NullLogger();

$worker = new Worker(
[
'foo' => static function (): void {
},
],
$logger,
new Injector($container),
$container,
new ConsumeMiddlewareDispatcher(new MiddlewareFactoryConsume($container, $callableFactory)),
new FailureMiddlewareDispatcher(
new MiddlewareFactoryFailure($container, $callableFactory),
[],
),
);
$this->serializer = new JsonMessageSerializer();
$this->adapter = new VoidAdapter($this->serializer);

$this->queue = new Queue(
$worker,
new SimpleLoop(0),
$logger,
new PushMiddlewareDispatcher(new MiddlewareFactoryPush($container, $callableFactory)),
$this->adapter,
);
}

public function providePush(): Generator
{
yield 'simple' => ['message' => new Message('foo', 'bar')];
yield 'with envelopes' => [
'message' => new FailureEnvelope(
new IdEnvelope(
new Message('foo', 'bar'),
'test id',
),
['failure-1' => ['a', 'b', 'c']],
),
];
}

#[ParamProviders('providePush')]
#[Tag('queue_push')]
public function benchPush(array $params): void
{
$this->queue->push($params['message']);
}

public function provideConsume(): Generator
{
yield 'simple mapping' => ['message' => $this->serializer->serialize(new Message('foo', 'bar'))];
yield 'with envelopes mapping' => [
'message' => $this->serializer->serialize(
new FailureEnvelope(
new IdEnvelope(
new Message('foo', 'bar'),
'test id',
),
['failure-1' => ['a', 'b', 'c']],
),
),
];
}

#[ParamProviders('provideConsume')]
#[Tag('queue_consume')]
public function benchConsume(array $params): void
{
$this->adapter->message = $params['message'];
$this->queue->run();
}
}
52 changes: 52 additions & 0 deletions tests/Benchmark/Support/VoidAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\Benchmark\Support;

use InvalidArgumentException;
use RuntimeException;
use Yiisoft\Queue\Adapter\AdapterInterface;
use Yiisoft\Queue\Enum\JobStatus;
use Yiisoft\Queue\Message\IdEnvelope;
use Yiisoft\Queue\Message\MessageInterface;
use Yiisoft\Queue\Message\MessageSerializerInterface;

final class VoidAdapter implements AdapterInterface
{
/**
* @var string A serialized message
*/
public string $message;

public function __construct(private MessageSerializerInterface $serializer)
{
}

public function runExisting(callable $handlerCallback): void
{
$handlerCallback($this->serializer->unserialize($this->message));
}

public function status(int|string $id): JobStatus
{
throw new InvalidArgumentException();
}

public function push(MessageInterface $message): MessageInterface
{
$this->serializer->serialize($message);

return new IdEnvelope($message, 1);
}

public function subscribe(callable $handlerCallback): void
{
throw new RuntimeException('Method is not implemented');
}

public function withChannel(string $channel): AdapterInterface
{
throw new RuntimeException('Method is not implemented');
}
}
12 changes: 7 additions & 5 deletions tests/docker/php/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# Important! Do not use this image in production!

ARG PHP_VERSION
FROM --platform=linux/amd64 php:${PHP_VERSION}-cli-alpine
FROM php:${PHP_VERSION}-cli-alpine

RUN apk add git autoconf g++ make linux-headers
RUN apk add git autoconf g++ make linux-headers && \
docker-php-ext-install pcntl && \
pecl install xdebug pcov && \
docker-php-ext-enable xdebug pcov

RUN docker-php-ext-install pcntl
RUN pecl install xdebug pcov
RUN docker-php-ext-enable xdebug pcov
ADD ./tests/docker/php/php.ini /usr/local/etc/php/conf.d/40-custom.ini

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
ENV COMPOSER_ALLOW_SUPERUSER 1

WORKDIR /app
RUN git config --global --add safe.directory /app
ENTRYPOINT ["sh", "tests/docker/php/entrypoint.sh"]
CMD ["sleep", "infinity"]
2 changes: 2 additions & 0 deletions tests/docker/php/php.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
opcache.enable=1
opcache.enable_cli=1

0 comments on commit e297466

Please sign in to comment.