Skip to content
Open
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
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ _**Todo:** Tests are working but could cover more._
6. [Dispatcher usage](#dispatcher-usage)
7. [Start workers daemon](#start-workers-daemon)
8. [Usage with Supervisor](#usage-with-supervisor)
9. [PHP 8.4 Compatibility](#php-8-4-compatibility)

<a name="requirements"></a>
## Requirements
Expand Down Expand Up @@ -191,3 +192,22 @@ numprocs=12
autostart=true
autorestart=true
```

<a name="php-8-4-compatibility"></a>
## PHP 8.4 Compatibility

This library has been updated to support PHP 8.4+ with the following improvements:

- Strong type declarations throughout the codebase
- Modern property declarations
- Updated serialization methods
- Improved error handling
- Modern dependency versions
- Strict typing enabled
- Updated PHPUnit testing suite

To use with PHP 8.4+, ensure you have:

- PHP 8.4 or higher
- Latest PECL Gearman extension
- Gearman 1.0+ server
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
}
],
"require": {
"php": ">=5.4.0",
"php": ">=8.1",
"ext-gearman": "*",
"psr/log": "~1",
"react/event-loop": "0.4.*",
"symfony/console": "2.*|3.4.*|4.1.*|5.*"
"psr/log": "^3.0",
"react/event-loop": "^1.4",
"symfony/console": "^6.0|^7.0"
},
"require-dev": {
"phpunit/phpunit": "~4"
"phpunit/phpunit": "^10.0"
},
"autoload": {
"psr-4": {
Expand Down
130 changes: 56 additions & 74 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
use GearmanJob;
use Psr\Log\LoggerInterface;
use React\EventLoop\Factory as Loop;
use React\EventLoop\LibEventLoop;
use React\EventLoop\StreamSelectLoop;
use React\EventLoop\LoopInterface;
use Serializable;
use Sinergi\Gearman\Exception\InvalidBootstrapClassException;

Expand All @@ -16,75 +15,74 @@ class Application implements Serializable
/**
* @var Config
*/
private $config;
private Config $config;

/**
* @var Process
*/
private $process;
private Process $process;

/**
* @var array
*/
private $callbacks = [];
private array $callbacks = [];

/**
* @var StreamSelectLoop|LibEventLoop
*/
private $loop;
private ?LoopInterface $loop = null;

/**
* @var bool|resource
*/
private $lock = false;
private bool|resource $lock = false;

/**
* @var bool
*/
private $kill = false;
private bool $kill = false;

/**
* @var Worker
*/
private $worker;
private ?Worker $worker = null;

/**
* @var array
*/
private $jobs = [];
private array $jobs = [];

/**
* @var LoggerInterface
*/
public $logger;
public ?LoggerInterface $logger = null;

/**
* @var bool
*/
public $isAllowingJob = false;
public bool $isAllowingJob = false;

/**
* @var bool
*/
public $isBootstraped = false;
public bool $isBootstraped = false;

/**
* @var Application
*/
private static $instance;
private static ?self $instance = null;

/**
* gets the instance via lazy initialization (created on first usage)
*
* @return self
*/
public static function getInstance()
public static function getInstance(): self
{
if (null === static::$instance) {
static::$instance = new static;
if (self::$instance === null) {
self::$instance = new self();
}

return static::$instance;
return self::$instance;
}

/**
Expand All @@ -93,23 +91,22 @@ public static function getInstance()
* @param Process $process
* @param LoggerInterface|null $logger
*/
public function __construct(Config $config = null, Process $process = null, $loop = null, LoggerInterface $logger = null)
{
static::$instance = $this;

if (null === $config) {
$config = Config::getInstance();
}
$this->setConfig($config);
public function __construct(
?Config $config = null,
?Process $process = null,
?LoopInterface $loop = null,
?LoggerInterface $logger = null
) {
self::$instance = $this;

if (null !== $logger) {
$this->setLogger($logger);
}

if (null !== $process) {
$this->config = $config ?? Config::getInstance();
$this->logger = $logger;

if ($process !== null) {
$this->setProcess($process);
}
if ($loop instanceof StreamSelectLoop || $loop instanceof LibEventLoop) {

if ($loop !== null) {
$this->setLoop($loop);
}
}
Expand Down Expand Up @@ -340,16 +337,19 @@ private function createLoop($restart = false)
* @param Application $root
* @return mixed
*/
public function executeJob(JobInterface $job, GearmanJob $gearmanJob, Application $root)
public function executeJob(JobInterface $job, GearmanJob $gearmanJob, self $root): mixed
{
if ($root->getConfig()->getAutoUpdate() && !$root->isAllowingJob) {
$root->restart();
return null;
}

$root->isAllowingJob = false;
if (null !== $root->logger) {

if ($root->logger !== null) {
$root->logger->info("Executing job {$job->getName()}");
}

return $job->execute($gearmanJob);
}

Expand Down Expand Up @@ -499,55 +499,37 @@ public function getProcess()
}

/**
* @return LoggerInterface
* @return string
*/
public function getLogger()
public function serialize(): string
{
return $this->logger;
return serialize($this->__serialize());
}

/**
* @param LoggerInterface $logger
* @return $this
*/
public function setLogger(LoggerInterface $logger)
public function __serialize(): array
{
$this->logger = $logger;
return $this;
return [
'config' => $this->config,
'process' => $this->process,
'callbacks' => $this->callbacks,
'jobs' => $this->jobs,
'isAllowingJob' => $this->isAllowingJob,
'isBootstraped' => $this->isBootstraped
];
}

/**
* @return string
*/
public function serialize()
public function unserialize(string $data): void
{
return serialize([
'config' => $this->getConfig(),
'isBootstraped' => false,
'isAllowingJob' => true
]);
$this->__unserialize(unserialize($data));
}

/**
* @param string $serialized
*/
public function unserialize($serialized)
public function __unserialize(array $data): void
{
$data = unserialize($serialized);

if (isset($data['config'])) {
$this->setConfig($data['config']);
}

$process = new Process($this->getConfig(), $this->getLogger());
$this->setProcess($process);

if (isset($data['isAllowingJob'])) {
$this->isAllowingJob = $data['isAllowingJob'];
}

if (isset($data['isBootstraped'])) {
$this->isBootstraped = $data['isBootstraped'];
}
$this->config = $data['config'];
$this->process = $data['process'];
$this->callbacks = $data['callbacks'];
$this->jobs = $data['jobs'];
$this->isAllowingJob = $data['isAllowingJob'];
$this->isBootstraped = $data['isBootstraped'];
}
}
45 changes: 26 additions & 19 deletions src/Worker.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?php
declare(strict_types=1);

namespace Sinergi\Gearman;

use GearmanException;
Expand All @@ -11,32 +13,32 @@ class Worker
/**
* @var GearmanWorker
*/
private $worker;
private ?GearmanWorker $worker = null;

/**
* @var Config
*/
private $config;
private Config $config;

/**
* @var LoggerInterface
*/
private $logger;
private ?LoggerInterface $logger;

/**
* @param Config $config
* @param null|LoggerInterface $logger
* @throws ServerConnectionException
*/
public function __construct(Config $config, LoggerInterface $logger = null)
{
$this->setConfig($config);
if (null !== $logger) {
$this->setLogger($logger);
}
public function __construct(
Config $config,
?LoggerInterface $logger = null
) {
$this->config = $config;
$this->logger = $logger;
}

public function resetWorker()
public function resetWorker(): void
{
if ($this->worker instanceof GearmanWorker) {
$this->worker->unregisterAll();
Expand All @@ -46,29 +48,34 @@ public function resetWorker()
}

/**
* @throws Exception\ServerConnectionException
* @throws ServerConnectionException
*/
private function createWorker()
private function createWorker(): void
{
$this->worker = new GearmanWorker();
$servers = $this->getConfig()->getServers();
$servers = $this->config->getServers();
$exceptions = [];

foreach ($servers as $server) {
try {
$this->worker->addServer($server->getHost(), $server->getPort());
} catch (GearmanException $e) {
$message = 'Unable to connect to Gearman Server ' . $server->getHost() . ':' . $server->getPort();
if (null !== $this->logger) {
$message = sprintf(
'Unable to connect to Gearman Server %s:%s',
$server->getHost(),
$server->getPort()
);

if ($this->logger !== null) {
$this->logger->info($message);
}

$exceptions[] = $message;
}
}

if (count($exceptions)) {
foreach ($exceptions as $exception) {
throw new ServerConnectionException($exception);
}
if (!empty($exceptions)) {
throw new ServerConnectionException(implode(', ', $exceptions));
}
}

Expand Down