Skip to content
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

Feat: add callback to check how many workers are available #34

Merged
merged 5 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/Informer/Worker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Spiral\RoadRunner\Informer;

final class Worker
{
/**
* @param positive-int $pid process id
* @param int $statusCode integer status of the worker
* @param int $executions number of worker executions
* @param positive-int $createdAt unix nano timestamp of worker creation time
* @param positive-int $memoryUsage memory usage in bytes. Values might vary for different operating systems and based on RSS
* @param float $cpuUsage how many percent of the CPU time this process uses
* @param string $command used in the service plugin and shows a command for the particular service
*/
public function __construct(
public int $pid,
public int $statusCode,
public int $executions,
public int $createdAt,
public int $memoryUsage,
public float $cpuUsage,
public string $command,
public string $status,
) {
}
}
21 changes: 21 additions & 0 deletions src/Informer/Workers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Spiral\RoadRunner\Informer;

final class Workers implements \Countable
{
/**
* @param array<Worker> $workers
*/
public function __construct(
public array $workers = [],
) {
}

public function count(): int
{
return \count($this->workers);
}
}
50 changes: 50 additions & 0 deletions src/WorkerPool.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,21 @@

use Spiral\Goridge\RPC\Codec\JsonCodec;
use Spiral\Goridge\RPC\RPCInterface;
use Spiral\RoadRunner\Informer\Workers;
use Spiral\RoadRunner\Informer\Worker as InformerWorker;

/**
* @psalm-type TInformerWorker = array{
* pid: positive-int,
* status: int,
* numExecs: int,
* created: positive-int,
* memoryUsage: positive-int,
* CPUPercent: float,
* command: string,
* statusStr: string,
* }
*/
final class WorkerPool
{
private readonly RPCInterface $rpc;
Expand All @@ -27,6 +41,42 @@ public function addWorker(string $plugin): void
$this->rpc->call('informer.AddWorker', $plugin);
}

/**
* Get the number of workers for the pool.
*
* @param non-empty-string $plugin
*/
public function countWorkers(string $plugin): int
{
return \count($this->getWorkers($plugin));
}

/**
* Get the info about running workers for the pool.
*
* @param non-empty-string $plugin
*/
public function getWorkers(string $plugin): Workers
{
/**
* @var array{workers: list<TInformerWorker>} $data
*/
$data = $this->rpc->call('informer.Workers', $plugin);

return new Workers(\array_map(static function (array $worker): InformerWorker {
return new InformerWorker(
pid: $worker['pid'],
statusCode: $worker['status'],
executions: $worker['numExecs'],
createdAt: $worker['created'],
memoryUsage: $worker['memoryUsage'],
cpuUsage: $worker['CPUPercent'],
command: $worker['command'],
status: $worker['statusStr'],
);
}, $data['workers']));
}

/**
* Remove worker from the pool.
*
Expand Down
75 changes: 73 additions & 2 deletions tests/Unit/WorkerPoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,28 @@

namespace Spiral\RoadRunner\Tests\Worker\Unit;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\TestCase;
use Spiral\Goridge\RPC\Codec\JsonCodec;
use Spiral\Goridge\RPC\RPCInterface;
use Spiral\RoadRunner\Informer\Worker;
use Spiral\RoadRunner\Informer\Workers;
use Spiral\RoadRunner\WorkerPool;

final class WorkerPoolTest extends TestCase
{
private const EXAMPLE_WORKER = [
'pid' => 1,
'status' => 1,
'numExecs' => 1,
'created' => 1,
'memoryUsage' => 1,
'CPUPercent' => 1.0,
'command' => 'test',
'statusStr' => 'test',
];

private \PHPUnit\Framework\MockObject\MockObject|RPCInterface $rpc;
private WorkerPool $workerPool;

Expand All @@ -23,7 +37,11 @@ protected function setUp(): void
parent::setUp();

$this->rpc = $this->createMock(RPCInterface::class);
$this->rpc->expects($this->once())->method('withCodec')->with($this->isInstanceOf(JsonCodec::class))->willReturnSelf();
$this->rpc
->expects($this->once())
->method('withCodec')
->with($this->isInstanceOf(JsonCodec::class))
->willReturnSelf();

$this->workerPool = new WorkerPool($this->rpc);
}
Expand All @@ -35,10 +53,63 @@ public function testAddWorker(): void
$this->workerPool->addWorker('test');
}

#[DataProvider('countDataProvider')]
public function testCountWorkers(int $expected, array $workers): void
{
$this->rpc
->expects($this->once())
->method('call')
->with('informer.Workers', 'test')
->willReturn(['workers' => $workers]);

$this->assertSame($expected, $this->workerPool->countWorkers('test'));
}

#[DataProvider('getWorkersDataProvider')]
public function testGetWorkers(array $expected, array $workers): void
{
$this->rpc
->expects($this->once())
->method('call')
->with('informer.Workers', 'test')
->willReturn(['workers' => $workers]);

$this->assertEquals(new Workers($expected), $this->workerPool->getWorkers('test'));
}

public function testRemoveWorker(): void
{
$this->rpc->expects($this->once())->method('call')->with('informer.RemoveWorker', 'test');

$this->workerPool->removeWorker('test');
}
}

public static function countDataProvider(): \Traversable
{
yield [0, []];
yield [2, [self::EXAMPLE_WORKER, self::EXAMPLE_WORKER]];
}

public static function getWorkersDataProvider(): \Traversable
{
yield [[], []];

$workers = \array_map(static function (array $worker): Worker {
return new Worker(
pid: $worker['pid'],
statusCode: $worker['status'],
executions: $worker['numExecs'],
createdAt: $worker['created'],
memoryUsage: $worker['memoryUsage'],
cpuUsage: $worker['CPUPercent'],
command: $worker['command'],
status: $worker['statusStr'],
);
}, [
self::EXAMPLE_WORKER,
self::EXAMPLE_WORKER,
]);

yield [$workers, [self::EXAMPLE_WORKER, self::EXAMPLE_WORKER]];
}
}
Loading