From af8de7d98b4fb77fdffb7bb1bd5bc9a1877db07c Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 00:56:51 +0200
Subject: [PATCH 01/59] Update to PHP 8.4 and new dependencies, and break
---
.github/workflows/phpunit.yml | 41 +++++++++++++
.gitignore | 1 +
Dockerfile | 39 ++++++++++---
Makefile | 47 +++++++++++++++
compose.yaml | 21 +++++++
composer.json | 58 +++++++++++--------
examples/bootstrap.php | 2 +-
phpstan.neon | 3 +-
rector.php | 17 ++++++
spec/Recruiter/Acceptance/AssignmentTest.php | 2 +-
...nceTest.php => BaseAcceptanceTestCase.php} | 7 ++-
spec/Recruiter/Acceptance/EnduranceTest.php | 4 +-
.../Acceptance/FaultToleranceTest.php | 2 +-
spec/Recruiter/Acceptance/HooksTest.php | 12 ++--
.../RepeatableJobsAreScheduledTest.php | 6 +-
.../Acceptance/SyncronousExecutionTest.php | 2 +-
...rGuaranteedToExitWhenAMemoryLeakOccurs.php | 4 +-
...itWithFailureCodeInCaseOfExceptionTest.php | 2 +-
...WorkerGuaranteedToRetireAfterDeathTest.php | 2 +-
.../Acceptance/WorkerRepositoryTest.php | 2 +-
...rkableImplementsFinalizerInterfaceTest.php | 2 +-
spec/Recruiter/Job/RepositoryTest.php | 13 +++--
spec/Recruiter/WaitStrategyTest.php | 2 +-
spec/Timeless/MongoDateTest.php | 2 +-
src/Recruiter/Job.php | 4 +-
src/Recruiter/Job/Event.php | 11 ++--
.../RetryPolicy/SelectByException.php | 1 -
src/Recruiter/Scheduler.php | 2 +-
src/Recruiter/SynchronousExecutionReport.php | 4 +-
src/Recruiter/functions.php | 22 +------
30 files changed, 235 insertions(+), 102 deletions(-)
create mode 100644 .github/workflows/phpunit.yml
create mode 100644 Makefile
create mode 100644 compose.yaml
create mode 100644 rector.php
rename spec/Recruiter/Acceptance/{BaseAcceptanceTest.php => BaseAcceptanceTestCase.php} (97%)
diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
new file mode 100644
index 00000000..9619b698
--- /dev/null
+++ b/.github/workflows/phpunit.yml
@@ -0,0 +1,41 @@
+name: PHPUnit Tests
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Validate composer.json and composer.lock
+ run: composer validate --strict
+
+ - name: Cache Composer packages
+ id: composer-cache
+ uses: actions/cache@v3
+ with:
+ path: vendor
+ key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-php-
+
+ - name: Build the Docker image
+ run: make build
+
+ - name: Install dependencies
+ run: make install
+
+ - name: Run test suite (except long ones)
+ run: make test
+
+ - name: Run test suite (only long ones)
+ run: make test-long
diff --git a/.gitignore b/.gitignore
index ff2779ce..62560d1e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.*
+!.github
composer.phar
composer.lock
vendor/
diff --git a/Dockerfile b/Dockerfile
index 7214a211..1904a3f9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,18 +1,39 @@
-FROM php:7.2-cli
+FROM php:8.4-cli
-RUN apt-get update \
- && apt-get install -y mongodb git
+# Install system dependencies
+RUN apt-get update && apt-get install -y \
+ git \
+ unzip \
+ libssl-dev \
+ libcurl4-openssl-dev \
+ pkg-config \
+ && rm -rf /var/lib/apt/lists/*
+# Install MongoDB extension
RUN pecl install mongodb \
- && docker-php-ext-install bcmath pdo_mysql mbstring opcache pcntl \
- && docker-php-ext-enable mongodb
+ && docker-php-ext-enable mongodb \
+ && docker-php-ext-install -j$(nproc) \
+ bcmath \
+ pdo_mysql \
+ opcache \
+ pcntl
-RUN curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composer && composer global require hirak/prestissimo --no-plugins --no-scripts
+# Copy Composer from official image
+COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
+# Set working directory
WORKDIR /app
-COPY . /app
+# Copy composer files
+COPY composer.json composer.lock* ./
-RUN composer install
+# Install dependencies including dev dependencies for testing
+RUN composer install --optimize-autoloader
-ENTRYPOINT /etc/init.d/mongodb start && vendor/bin/phpunit
+# Copy application code
+COPY . .
+
+# Set environment variable for Composer
+ENV COMPOSER_ALLOW_SUPERUSER=1
+
+CMD ["tail", "-f", "/dev/null"]
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..ca10c565
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,47 @@
+.PHONY: build up down test phpstan rector fix-cs install update shell logs clean
+
+# Build the Docker image
+build:
+ docker compose build
+
+# Start the services
+up:
+ docker compose up -d
+
+# Stop the services
+down:
+ docker compose down
+
+# Install dependencies
+install:
+ docker compose run --rm php composer install
+
+# Update dependencies
+update:
+ docker compose run --rm php composer update
+
+# Run all tests except the long ones
+test: up
+ docker compose exec php vendor/bin/phpunit
+
+phpstan: up
+ docker compose exec php vendor/bin/phpstan
+
+rector: up
+ docker compose exec php vendor/bin/rector
+
+fix-cs: up
+ docker compose exec php vendor/bin/php-cs-fixer fix -v
+
+# Open a shell in the PHP container
+shell:
+ docker compose exec php bash
+
+# View logs
+logs:
+ docker compose logs -f php
+
+# Clean up containers and volumes
+clean:
+ docker compose down -v
+ docker compose rm -f
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 00000000..463cd86c
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,21 @@
+services:
+ php:
+ build: .
+ working_dir: /app
+ volumes:
+ - .:/app
+ environment:
+ - COMPOSER_ALLOW_SUPERUSER=1
+ - MONGODB_URI=mongodb://mongodb:27017/concurrency
+ depends_on:
+ - mongodb
+
+ mongodb:
+ image: mongo:8
+ container_name: recruiter_mongodb
+ restart: unless-stopped
+ volumes:
+ - mongodb_data:/data/db
+
+volumes:
+ mongodb_data:
diff --git a/composer.json b/composer.json
index 95fb02e3..85701f2d 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,7 @@
{
"name": "recruiterphp/recruiter",
"description": "Job Queue Manager: high performance, high volume, persistent, fault tolerant. 100% PHP/MongoDB, 100% Awesome",
+ "license": "MIT",
"type": "project",
"keywords": [
"job",
@@ -13,8 +14,6 @@
"manager",
"mongodb"
],
- "homepage": "https://github.com/recruiterphp/recruiter",
- "license": "MIT",
"authors": [
{
"name": "gabriele.lana",
@@ -25,44 +24,53 @@
"homepage": "https://github.com/recruiterphp/recruiter/graphs/contributors"
}
],
+ "homepage": "https://github.com/recruiterphp/recruiter",
"require": {
- "php": "~7.2",
+ "php": "^8.4",
"ext-mongodb": ">=1.1",
- "alcaeus/mongo-php-adapter": "^1.1",
- "recruiterphp/geezer": "^5",
- "gabrielelana/byte-units": "~0.1",
- "monolog/monolog": ">=1",
- "recruiterphp/concurrency": "^3.0",
- "psr/log": "^1.0",
- "symfony/console": "^4.2",
- "symfony/event-dispatcher": "^3.4|^4.0",
- "ulrichsg/getopt-php": "~2.1",
- "mongodb/mongodb": "^1.4",
- "mtdowling/cron-expression": "^1.2"
- },
- "suggest": {
- "symfony/console": "In order to use Recruiter\\Command\\RecruiterJobCommand."
+ "dragonmantank/cron-expression": "^3.4",
+ "gabrielelana/byte-units": "^0.5",
+ "mongodb/mongodb": "^2.1",
+ "monolog/monolog": "^3.9",
+ "psr/log": "^3.0",
+ "recruiterphp/concurrency": "^4.0",
+ "recruiterphp/geezer": "^6.0",
+ "symfony/console": "^7.3",
+ "symfony/event-dispatcher": "^7.3",
+ "ulrichsg/getopt-php": "^4.0"
},
"require-dev": {
- "phpunit/phpunit": "^8",
+ "dms/phpunit-arraysubset-asserts": "^0.5",
+ "ergebnis/composer-normalize": "^2.47",
+ "giorgiosironi/eris": "^1.0",
"phpstan/phpstan": "*",
- "giorgiosironi/eris": "dev-master",
- "dms/phpunit-arraysubset-asserts": "^0.1.0"
+ "phpunit/phpunit": "^10.0",
+ "rector/rector": "^2.1",
+ "ext-pcntl": "*"
+ },
+ "suggest": {
+ "symfony/console": "In order to use Recruiter\\Command\\RecruiterJobCommand."
},
"minimum-stability": "dev",
"prefer-stable": true,
- "bin": [
- "bin/recruiter"
- ],
"autoload": {
"psr-4": {
"Recruiter\\": "src/Recruiter",
- "Timeless\\": "src/Timeless",
- "Sink\\": "src/Sink"
+ "Sink\\": "src/Sink",
+ "Timeless\\": "src/Timeless"
},
"files": [
"src/Timeless/functions.php",
"src/Recruiter/functions.php"
]
+ },
+ "bin": [
+ "bin/recruiter"
+ ],
+ "config": {
+ "allow-plugins": {
+ "ergebnis/composer-normalize": true
+ },
+ "sort-packages": true
}
}
diff --git a/examples/bootstrap.php b/examples/bootstrap.php
index 5e278a1e..c61635fd 100644
--- a/examples/bootstrap.php
+++ b/examples/bootstrap.php
@@ -1,6 +1,6 @@
getEventDispatcher()->addListener('job.failure.last', function($event) {
+$recruiter->getEventDispatcher()->addListener('job.failure.last', function($event): void {
error_log("Job definitively failed: " . var_export($event->export(), true));
});
diff --git a/phpstan.neon b/phpstan.neon
index 4e803c3c..010afda7 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -2,8 +2,7 @@ parameters:
level: max
paths:
- src
- excludes_analyse:
- - %currentWorkingDirectory%/vendor/
+ - tests
autoload_directories:
- %currentWorkingDirectory%/spec
ignoreErrors:
diff --git a/rector.php b/rector.php
new file mode 100644
index 00000000..b2252895
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,17 @@
+withPaths([
+ __DIR__ . '/examples',
+ __DIR__ . '/spec',
+ __DIR__ . '/src',
+ ])
+ // uncomment to reach your current PHP version
+ // ->withPhpSets()
+ ->withTypeCoverageLevel(0)
+ ->withDeadCodeLevel(0)
+ ->withCodeQualityLevel(0);
diff --git a/spec/Recruiter/Acceptance/AssignmentTest.php b/spec/Recruiter/Acceptance/AssignmentTest.php
index c7f08a3a..e173d909 100644
--- a/spec/Recruiter/Acceptance/AssignmentTest.php
+++ b/spec/Recruiter/Acceptance/AssignmentTest.php
@@ -4,7 +4,7 @@
use Recruiter\Infrastructure\Memory\MemoryLimit;
use Recruiter\Workable\LazyBones;
-class AssignmentTest extends BaseAcceptanceTest
+class AssignmentTest extends BaseAcceptanceTestCase
{
public function testAJobCanBeAssignedAndExecuted()
{
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTest.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
similarity index 97%
rename from spec/Recruiter/Acceptance/BaseAcceptanceTest.php
rename to spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index 347be835..3be74e46 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTest.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -11,7 +11,7 @@
use Recruiter\Workable\ShellCommand;
use Timeless as T;
-abstract class BaseAcceptanceTest extends TestCase
+abstract class BaseAcceptanceTestCase extends TestCase
{
protected $recruiterDb;
@@ -24,7 +24,8 @@ abstract class BaseAcceptanceTest extends TestCase
public function setUp(): void
{
$factory = new Factory();
- $this->recruiterDb = $factory->getMongoDb(MongoURI::from('mongodb://localhost:27017/recruiter'), []);
+ $uri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
+ $this->recruiterDb = $factory->getMongoDb(MongoURI::from($uri), []);
$this->cleanDb();
$this->files = ['/tmp/recruiter.log', '/tmp/worker.log'];
$this->cleanLogs();
@@ -178,7 +179,7 @@ protected function enqueueJob($duration = 10, $tag = 'generic')
$this->jobs++;
}
- protected function enqueueJobWithRetryPolicy($duration = 10, RetryPolicy $retryPolicy)
+ protected function enqueueJobWithRetryPolicy(int $duration, RetryPolicy $retryPolicy): void
{
$workable = ShellCommand::fromCommandLine("sleep " . ($duration / 1000));
$workable
diff --git a/spec/Recruiter/Acceptance/EnduranceTest.php b/spec/Recruiter/Acceptance/EnduranceTest.php
index 3ef3a43c..b71e3e29 100644
--- a/spec/Recruiter/Acceptance/EnduranceTest.php
+++ b/spec/Recruiter/Acceptance/EnduranceTest.php
@@ -12,7 +12,7 @@
/**
* @group long
*/
-class EnduranceTest extends BaseAcceptanceTest
+class EnduranceTest extends BaseAcceptanceTestCase
{
use Eris\TestTrait;
@@ -73,7 +73,7 @@ function ($milliseconds) {
->hook(Listener\log('/tmp/recruiter-test-iterations.log'))
->hook(Listener\collectFrequencies())
->disableShrinking()
- ->then(function ($tuple) {
+ ->then(function ($tuple): void {
list ($workers, $actions) = $tuple;
$this->clean();
$this->start($workers);
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index d71afafe..9e2daaa8 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -8,7 +8,7 @@
use Recruiter\RetryPolicy\RetryManyTimes;
use Timeless as T;
-class FaultToleranceTest extends BaseAcceptanceTest
+class FaultToleranceTest extends BaseAcceptanceTestCase
{
public function testRecruiterCrashAfterLockingJobsBeforeAssignmentAndIsRestarted()
{
diff --git a/spec/Recruiter/Acceptance/HooksTest.php b/spec/Recruiter/Acceptance/HooksTest.php
index 05266dcf..e66b9899 100644
--- a/spec/Recruiter/Acceptance/HooksTest.php
+++ b/spec/Recruiter/Acceptance/HooksTest.php
@@ -7,7 +7,7 @@
use Recruiter\RetryPolicy\RetryManyTimes;
use Symfony\Component\EventDispatcher\Event;
-class HooksTest extends BaseAcceptanceTest
+class HooksTest extends BaseAcceptanceTestCase
{
public function setUp(): void
{
@@ -22,7 +22,7 @@ public function testAfterFailureWithoutRetryEventIsFired()
->getEventDispatcher()
->addListener(
'job.failure.last',
- function (Event $event) {
+ function (Event $event): void {
$this->events[] = $event;
}
);
@@ -48,7 +48,7 @@ public function testAfterLastFailureEventIsFired()
->getEventDispatcher()
->addListener(
'job.failure.last',
- function (Event $event) {
+ function (Event $event): void {
$this->events[] = $event;
}
);
@@ -59,7 +59,7 @@ function (Event $event) {
->inBackground()
->execute();
- $runAJob = function ($howManyTimes, $worker) {
+ $runAJob = function ($howManyTimes, $worker): void {
for ($i = 0; $i < $howManyTimes;) {
list($_, $assigned) = $this->recruiter->assignJobsToWorkers();
$worker->work();
@@ -84,7 +84,7 @@ public function testJobStartedIsFired()
->getEventDispatcher()
->addListener(
'job.started',
- function (Event $event) {
+ function (Event $event): void {
$this->events[] = $event;
}
);
@@ -109,7 +109,7 @@ public function testJobEndedIsFired()
->getEventDispatcher()
->addListener(
'job.ended',
- function (Event $event) {
+ function (Event $event): void {
$this->events[] = $event;
}
);
diff --git a/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php b/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
index 7d1a29b4..abce5a0c 100644
--- a/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
+++ b/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
@@ -12,7 +12,7 @@
use Timeless as T;
use Timeless\Moment;
-class RepeatableJobsAreScheduledTest extends BaseAcceptanceTest
+class RepeatableJobsAreScheduledTest extends BaseAcceptanceTestCase
{
use ArraySubsetAsserts;
@@ -144,7 +144,7 @@ private function IHaveAScheduleWithALongStory(string $urn, $attempts)
$this->recruiterScheduleJobsNTimes($attempts);
}
- private function scheduleAJob(string $urn, SchedulePolicy $schedulePolicy = null, bool $unique = false)
+ private function scheduleAJob(string $urn, ?SchedulePolicy $schedulePolicy = null, bool $unique = false)
{
if (is_null($schedulePolicy)) {
$schedulePolicy = new FixedSchedulePolicy(strtotime('2023-02-18T17:00:00'));
@@ -160,7 +160,7 @@ private function scheduleAJob(string $urn, SchedulePolicy $schedulePolicy = null
return $scheduler->create();
}
- private function recruiterScheduleJobsNTimes(int $nth = 1)
+ private function recruiterScheduleJobsNTimes(int $nth = 1): void
{
$i = 0;
while ($i++ < $nth) {
diff --git a/spec/Recruiter/Acceptance/SyncronousExecutionTest.php b/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
index e1898b5b..6161ff16 100644
--- a/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
+++ b/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
@@ -5,7 +5,7 @@
use Recruiter\Workable\FactoryMethodCommand;
use Timeless as T;
-class SyncronousExecutionTest extends BaseAcceptanceTest
+class SyncronousExecutionTest extends BaseAcceptanceTestCase
{
public function testJobsAreExecutedInOrderOfScheduling()
{
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
index f6121ab2..5ceab2d7 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
@@ -6,7 +6,7 @@
use Recruiter\Workable\ConsumingMemoryCommand;
use Timeless as T;
-class WorkerGuaranteedToExitWhenAMemoryLeakOccurs extends BaseAcceptanceTest
+class WorkerGuaranteedToExitWhenAMemoryLeakOccurs extends BaseAcceptanceTestCase
{
/**
* @group acceptance
@@ -30,7 +30,7 @@ public function testWorkerKillItselfAfterAMemoryLeakButNotAfterABigMemoryConsump
]);
$this->waitForNumberOfWorkersToBe($numberOfWorkersBefore + 1, 5);
- Timeout::inSeconds(5, function () {
+ Timeout::inSeconds(5, function (): void {
})
->until(function () {
$at = T\now();
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
index e066a577..fcb0feb9 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
@@ -5,7 +5,7 @@
use Recruiter\Workable\FactoryMethodCommand;
use Recruiter\Workable\ThrowsFatalError;
-class WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest extends BaseAcceptanceTest
+class WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest extends BaseAcceptanceTestCase
{
/**
* @group acceptance
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
index 95ca3c9f..68d18a71 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
@@ -2,7 +2,7 @@
namespace Recruiter\Acceptance;
-class WorkerGuaranteedToRetireAfterDeathTest extends BaseAcceptanceTest
+class WorkerGuaranteedToRetireAfterDeathTest extends BaseAcceptanceTestCase
{
/**
* @group acceptance
diff --git a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
index 3364f238..f1918982 100644
--- a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
+++ b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
@@ -5,7 +5,7 @@
use Recruiter\Worker\Repository;
use Recruiter\Recruiter;
-class WorkerRepositoryTest extends BaseAcceptanceTest
+class WorkerRepositoryTest extends BaseAcceptanceTestCase
{
public function setUp(): void
{
diff --git a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
index 3a60e5fc..aa786638 100644
--- a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
+++ b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
@@ -31,7 +31,7 @@ public function testFinalizableFailureMethodsAreCalledWhenJobFails()
[$this->equalTo('afterLastFailure'), $exception],
[$this->equalTo('finalize'), $exception]
);
- $workable = new FinalizableWorkable(function () use ($exception) {
+ $workable = new FinalizableWorkable(function () use ($exception): void {
throw $exception;
}, $listener);
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 39153943..e4069a70 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -3,6 +3,7 @@
use DateTime;
use MongoDB\BSON\ObjectId;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Recruiter\Factory;
use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
@@ -455,10 +456,10 @@ private function jobExecutionMock($executionParameters)
}
private function jobMockWithAttemptsAndCustomParameters(
- Moment $createdAt = null,
- Moment $endedAt = null,
- array $workableParameters = null
- ) {
+ ?Moment $createdAt = null,
+ ?Moment $endedAt = null,
+ ?array $workableParameters = null
+ ): Job&MockObject {
$parameters = [
'_id' => new ObjectId(),
'created_at' => T\MongoDate::from($createdAt),
@@ -482,12 +483,12 @@ private function jobMockWithAttemptsAndCustomParameters(
$parameters['workable']['parameters'] = $workableParameters;
}
$job = $this
- ->getMockBuilder('Recruiter\Job')
+ ->getMockBuilder(Job::class)
->disableOriginalConstructor()
->getMock();
$job->expects($this->once())
->method('export')
- ->will($this->returnValue($parameters));
+ ->willReturn($parameters);
return $job;
}
}
diff --git a/spec/Recruiter/WaitStrategyTest.php b/spec/Recruiter/WaitStrategyTest.php
index b721e1dd..e6a305d4 100644
--- a/spec/Recruiter/WaitStrategyTest.php
+++ b/spec/Recruiter/WaitStrategyTest.php
@@ -10,7 +10,7 @@ class WaitStrategyTest extends TestCase
public function setUp(): void
{
$this->waited = 0;
- $this->howToWait = function($microseconds) {
+ $this->howToWait = function($microseconds): void {
$this->waited = T\milliseconds($microseconds/1000);
};
$this->timeToWaitAtLeast = T\milliseconds(250);
diff --git a/spec/Timeless/MongoDateTest.php b/spec/Timeless/MongoDateTest.php
index 093556e1..baecddf2 100644
--- a/spec/Timeless/MongoDateTest.php
+++ b/spec/Timeless/MongoDateTest.php
@@ -15,7 +15,7 @@ public function testConvertsBackAndForthMongoDatesWithoutLosingMillisecondPrecis
->forAll(
Generator\choose(0, 1500 * 1000 * 1000)
)
- ->then(function ($milliseconds) {
+ ->then(function ($milliseconds): void {
$moment = new Moment($milliseconds);
$this->assertEquals(
$moment,
diff --git a/src/Recruiter/Job.php b/src/Recruiter/Job.php
index ba95b6a7..7c278739 100644
--- a/src/Recruiter/Job.php
+++ b/src/Recruiter/Job.php
@@ -241,10 +241,10 @@ private function afterFailure($exception, $eventDispatcher)
return $archived;
}
- private function emit($eventType, $eventDispatcher)
+ private function emit($eventType, EventDispatcherInterface $eventDispatcher): void
{
$event = new Event($this->export());
- $eventDispatcher->dispatch($eventType, $event);
+ $eventDispatcher->dispatch($event, $eventType);
if ($this->workable instanceof EventListener) {
$this->workable->onEvent($eventType, $event);
}
diff --git a/src/Recruiter/Job/Event.php b/src/Recruiter/Job/Event.php
index 71738ebe..094a0f3c 100644
--- a/src/Recruiter/Job/Event.php
+++ b/src/Recruiter/Job/Event.php
@@ -1,23 +1,20 @@
jobExport = $jobExport;
}
- public function export()
+ public function export(): array
{
return $this->jobExport;
}
- public function hasTag($wantedTag)
+ public function hasTag(string $wantedTag): bool
{
$tags = array_key_exists('tags', $this->jobExport) ? $this->jobExport['tags'] : [];
return in_array($wantedTag, $tags);
diff --git a/src/Recruiter/RetryPolicy/SelectByException.php b/src/Recruiter/RetryPolicy/SelectByException.php
index c38835cb..0a2841db 100644
--- a/src/Recruiter/RetryPolicy/SelectByException.php
+++ b/src/Recruiter/RetryPolicy/SelectByException.php
@@ -8,7 +8,6 @@
use Recruiter\JobAfterFailure;
use Recruiter\RetryPolicy;
use Throwable;
-use function Recruiter\array_all;
/**
* Select retry policies based on the raised exception
diff --git a/src/Recruiter/Scheduler.php b/src/Recruiter/Scheduler.php
index 01b272db..3c5a73e1 100644
--- a/src/Recruiter/Scheduler.php
+++ b/src/Recruiter/Scheduler.php
@@ -151,7 +151,7 @@ public function schedule(JobsRepository $jobs)
$this->status['last_scheduling']['scheduled_at'] = T\MongoDate::from($nextScheduling);
$this->status['last_scheduling']['job_id'] = null;
- $this->status['attempts'] = $this->status['attempts'] + 1;
+ $this->status['attempts'] += 1;
$this->schedulers->save($this);
$jobToSchedule = (new JobToSchedule(Job::around($this->repeatable, $jobs)))
diff --git a/src/Recruiter/SynchronousExecutionReport.php b/src/Recruiter/SynchronousExecutionReport.php
index ebd1ac46..68132ed6 100644
--- a/src/Recruiter/SynchronousExecutionReport.php
+++ b/src/Recruiter/SynchronousExecutionReport.php
@@ -30,9 +30,9 @@ public static function fromArray(array $data): SynchronousExecutionReport
return new self($data);
}
- public function isThereAFailure()
+ public function isThereAFailure(): bool
{
- return array_some($this->data, function ($jobExecution, $jobId) {
+ return array_any($this->data, function ($jobExecution, $jobId) {
return $jobExecution->isFailed();
});
}
diff --git a/src/Recruiter/functions.php b/src/Recruiter/functions.php
index 115728df..f09bb232 100644
--- a/src/Recruiter/functions.php
+++ b/src/Recruiter/functions.php
@@ -1,27 +1,7 @@
$value) {
- if (!call_user_func($predicate, $value, $key, $array)) {
- return false;
- }
- }
- return true;
-}
-
-function array_some($array, callable $predicate)
-{
- foreach ($array as $key => $value) {
- if (call_user_func($predicate, $value, $key, $array)) {
- return true;
- }
- }
- return false;
-}
-
-function array_group_by($array, callable $f = null)
+function array_group_by($array, ?callable $f = null): array
{
$f = $f ?: function ($value) {
return $value;
From 1379ee5ad362f546a3dfd839b9d90b9afb4d6958 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 01:03:23 +0200
Subject: [PATCH 02/59] Fix types in BaseAcceptanceTestCase
---
.../Acceptance/BaseAcceptanceTestCase.php | 61 ++++++++++---------
1 file changed, 33 insertions(+), 28 deletions(-)
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index 3be74e46..5f90e0cb 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -2,6 +2,8 @@
namespace Recruiter\Acceptance;
use DateTimeImmutable;
+use MongoDB\Collection;
+use MongoDB\Database;
use Recruiter\Concurrency\Timeout;
use PHPUnit\Framework\TestCase;
use Recruiter\Factory;
@@ -13,15 +15,18 @@
abstract class BaseAcceptanceTestCase extends TestCase
{
- protected $recruiterDb;
-
- protected $recruiter;
- protected $scheduled;
- protected $archived;
- protected $roster;
- protected $schedulers;
-
- public function setUp(): void
+ protected Database $recruiterDb;
+ protected Recruiter $recruiter;
+ protected Collection $scheduled;
+ protected Collection $archived;
+ protected Collection $roster;
+ protected Collection $schedulers;
+ private ?array $processRecruiter;
+ private ?array $processCleaner;
+ private array $processWorkers;
+ private array $lastStatus;
+
+ protected function setUp(): void
{
$factory = new Factory();
$uri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
@@ -40,17 +45,17 @@ public function setUp(): void
$this->processWorkers = [];
}
- public function tearDown(): void
+ protected function tearDown(): void
{
$this->terminateProcesses(SIGKILL);
}
- protected function cleanDb()
+ protected function cleanDb(): void
{
$this->recruiterDb->drop();
}
- protected function clean()
+ protected function clean(): void
{
$this->terminateProcesses(SIGKILL);
$this->cleanLogs();
@@ -58,7 +63,7 @@ protected function clean()
$this->jobs = 0;
}
- public function cleanLogs()
+ public function cleanLogs(): void
{
foreach ($this->files as $file) {
if (file_exists($file)) {
@@ -67,12 +72,12 @@ public function cleanLogs()
}
}
- protected function numberOfWorkers()
+ protected function numberOfWorkers(): int
{
- return $this->roster->count();
+ return $this->roster->countDocuments();
}
- protected function waitForNumberOfWorkersToBe($expectedNumber, $howManySeconds = 1)
+ protected function waitForNumberOfWorkersToBe($expectedNumber, $howManySeconds = 1): void
{
Timeout::inSeconds($howManySeconds, "workers to be $expectedNumber")
->until(function () use ($expectedNumber) {
@@ -81,7 +86,7 @@ protected function waitForNumberOfWorkersToBe($expectedNumber, $howManySeconds =
});
}
- protected function startRecruiter()
+ protected function startRecruiter(): array
{
$descriptors = [
0 => ['pipe', 'r'],
@@ -103,7 +108,7 @@ protected function startRecruiter()
return $this->processRecruiter;
}
- protected function startCleaner()
+ protected function startCleaner(): array
{
$descriptors = [
0 => ['pipe', 'r'],
@@ -150,7 +155,7 @@ protected function startWorker(array $additionalOptions = [])
return end($this->processWorkers);
}
- protected function stopProcessWithSignal(array $processAndPipes, $signal)
+ protected function stopProcessWithSignal(array $processAndPipes, $signal): void
{
list($process, $pipes, $name) = $processAndPipes;
proc_terminate($process, $signal);
@@ -168,7 +173,7 @@ protected function stopProcessWithSignal(array $processAndPipes, $signal)
/**
* @param integer $duration milliseconds
*/
- protected function enqueueJob($duration = 10, $tag = 'generic')
+ protected function enqueueJob($duration = 10, $tag = 'generic'): void
{
$workable = ShellCommand::fromCommandLine("sleep " . ($duration / 1000));
$workable
@@ -190,7 +195,7 @@ protected function enqueueJobWithRetryPolicy(int $duration, RetryPolicy $retryPo
$this->jobs++;
}
- protected function start($workers)
+ protected function start(int $workers): void
{
$this->startRecruiter();
$this->startCleaner();
@@ -199,7 +204,7 @@ protected function start($workers)
}
}
- private function terminateProcesses($signal)
+ private function terminateProcesses($signal): void
{
if ($this->processRecruiter) {
$this->stopProcessWithSignal($this->processRecruiter, $signal);
@@ -215,31 +220,31 @@ private function terminateProcesses($signal)
$this->processWorkers = [];
}
- protected function restartWorkerGracefully($workerIndex)
+ protected function restartWorkerGracefully($workerIndex): void
{
$this->stopProcessWithSignal($this->processWorkers[$workerIndex], SIGTERM);
$this->processWorkers[$workerIndex] = $this->startWorker();
}
- protected function restartWorkerByKilling($workerIndex)
+ protected function restartWorkerByKilling($workerIndex): void
{
$this->stopProcessWithSignal($this->processWorkers[$workerIndex], SIGKILL);
$this->processWorkers[$workerIndex] = $this->startWorker();
}
- protected function restartRecruiterGracefully()
+ protected function restartRecruiterGracefully(): void
{
$this->stopProcessWithSignal($this->processRecruiter, SIGTERM);
$this->startRecruiter();
}
- protected function restartRecruiterByKilling()
+ protected function restartRecruiterByKilling(): void
{
$this->stopProcessWithSignal($this->processRecruiter, SIGKILL);
$this->startRecruiter();
}
- protected function files()
+ protected function files(): string
{
$logs = '';
if (getenv('TEST_DUMP')) {
@@ -253,7 +258,7 @@ protected function files()
return $logs;
}
- private function optionsToString(array $options = [])
+ private function optionsToString(array $options = []): string
{
$optionsString = '';
From ae8a99a39817f41069d79e439e07eab146193585 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 01:24:10 +0200
Subject: [PATCH 03/59] Get MONGODB_URI from environment
---
compose.yaml | 2 +-
.../Acceptance/BaseAcceptanceTestCase.php | 5 ++--
spec/Recruiter/FactoryTest.php | 27 +++++--------------
spec/Recruiter/Job/RepositoryTest.php | 15 ++++++-----
4 files changed, 19 insertions(+), 30 deletions(-)
diff --git a/compose.yaml b/compose.yaml
index 463cd86c..61c32cee 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -6,7 +6,7 @@ services:
- .:/app
environment:
- COMPOSER_ALLOW_SUPERUSER=1
- - MONGODB_URI=mongodb://mongodb:27017/concurrency
+ - MONGODB_URI=mongodb://mongodb:27017/recruiter
depends_on:
- mongodb
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index 5f90e0cb..50785542 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -7,6 +7,7 @@
use Recruiter\Concurrency\Timeout;
use PHPUnit\Framework\TestCase;
use Recruiter\Factory;
+use Recruiter\Infrastructure\Persistence\Mongodb\URI;
use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
use Recruiter\Recruiter;
use Recruiter\RetryPolicy;
@@ -29,7 +30,7 @@ abstract class BaseAcceptanceTestCase extends TestCase
protected function setUp(): void
{
$factory = new Factory();
- $uri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
+ $uri = getenv('MONGODB_URI') ?: URI::DEFAULT_URI;
$this->recruiterDb = $factory->getMongoDb(MongoURI::from($uri), []);
$this->cleanDb();
$this->files = ['/tmp/recruiter.log', '/tmp/worker.log'];
@@ -204,7 +205,7 @@ protected function start(int $workers): void
}
}
- private function terminateProcesses($signal): void
+ private function terminateProcesses(int $signal): void
{
if ($this->processRecruiter) {
$this->stopProcessWithSignal($this->processRecruiter, $signal);
diff --git a/spec/Recruiter/FactoryTest.php b/spec/Recruiter/FactoryTest.php
index 293f1623..ba94ff80 100644
--- a/spec/Recruiter/FactoryTest.php
+++ b/spec/Recruiter/FactoryTest.php
@@ -2,32 +2,19 @@
namespace Recruiter;
-use MongoDB;
+use MongoDB\Database;
use PHPUnit\Framework\TestCase;
use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
class FactoryTest extends TestCase
{
- /**
- * @var Factory
- */
- private $factory;
-
- /**
- * @var string
- */
- private $dbHost;
-
- /**
- * @var string
- */
- private $dbName;
+ private Factory $factory;
+ private MongoURI $mongoURI;
protected function setUp(): void
{
$this->factory = new Factory();
- $this->dbHost = 'localhost:27017';
- $this->dbName = 'recruiter';
+ $this->mongoURI = MongoURI::from(getenv('MONGODB_URI') ?: MongoURI::DEFAULT_URI);
}
public function testShouldCreateAMongoDatabaseConnection()
@@ -47,7 +34,7 @@ public function testWriteConcernIsMajorityByDefault()
public function testShouldOverwriteTheWriteConcernPassedInTheOptions()
{
$mongoDb = $this->factory->getMongoDb(
- MongoURI::from('mongodb://localhost:27017/recruiter'),
+ $this->mongoURI,
[
'connectTimeoutMS' => 1000,
'w' => '0',
@@ -57,10 +44,10 @@ public function testShouldOverwriteTheWriteConcernPassedInTheOptions()
$this->assertEquals('majority', $mongoDb->getWriteConcern()->getW());
}
- private function creationOfDefaultMongoDb()
+ private function creationOfDefaultMongoDb(): Database
{
return $this->factory->getMongoDb(
- MongoURI::from(sprintf('mongodb://%s/%s', $this->dbHost, $this->dbName)),
+ $this->mongoURI,
[
'connectTimeoutMS' => 1000,
'w' => '0',
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index e4069a70..0254b20f 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -1,31 +1,32 @@
recruiterDb = $factory->getMongoDb(MongoURI::from('mongodb://localhost:27017/recruiter'), []);
+ $this->recruiterDb = $factory->getMongoDb(MongoURI::from(getenv('MONGODB_URI') ?: MongoURI::DEFAULT_URI), []);
$this->recruiterDb->drop();
$this->repository = new Repository($this->recruiterDb);
$this->clock = T\clock()->stop();
- $this->eventDispatcher = $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+ $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
}
public function tearDown(): void
From b9ac8876f0d421a2db1305fc897667cf138bc8a6 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 01:27:31 +0200
Subject: [PATCH 04/59] Try to fix phpstan
---
Makefile | 2 +-
phpstan.neon | 8 +++-----
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/Makefile b/Makefile
index ca10c565..3df22988 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ test: up
docker compose exec php vendor/bin/phpunit
phpstan: up
- docker compose exec php vendor/bin/phpstan
+ docker compose exec php vendor/bin/phpstan --memory-limit=2G
rector: up
docker compose exec php vendor/bin/rector
diff --git a/phpstan.neon b/phpstan.neon
index 010afda7..e4015b46 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -2,16 +2,14 @@ parameters:
level: max
paths:
- src
- - tests
- autoload_directories:
- - %currentWorkingDirectory%/spec
+ - spec
ignoreErrors:
- '#Instantiated class Recruiter\\Workable\\ThisClassDoesnNotExists not found.#'
- '#Constructor of class Recruiter\\Workable\\FailsInConstructor has an unused parameter \$parameters.#'
- - '#Static call to instance method stdClass::import()#'
+ - '#Static call to instance method stdClass::import\(\)#'
- '#Call to function is_callable\(\) with .recruiter_stept_back. will always evaluate to false.#'
- '#Call to function is_callable\(\) with .recruiter_becameā¦. will always evaluate to false.#'
- '#Function recruiter_became_master not found.#'
- '#Function recruiter_stept_back not found.#'
- - '#Call to an undefined method Traversable::toArray().#'
+ - '#Call to an undefined method Traversable::toArray\(\).#'
inferPrivatePropertyTypeFromConstructor: true
From a42cc0673f5fdff1d16d4234faa5fc4a4f87ed76 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 02:01:00 +0200
Subject: [PATCH 05/59] Fix more types
---
composer.json | 3 +-
spec/Recruiter/Acceptance/AssignmentTest.php | 2 +-
spec/Recruiter/Acceptance/EnduranceTest.php | 2 +-
src/Sink/BlackHole.php | 36 ++++----
src/Timeless/Clock.php | 8 +-
src/Timeless/ClockInterface.php | 8 ++
src/Timeless/Interval.php | 90 +++++++++-----------
src/Timeless/Moment.php | 39 ++++-----
src/Timeless/StoppedClock.php | 13 ++-
src/Timeless/functions.php | 39 ++++-----
10 files changed, 119 insertions(+), 121 deletions(-)
create mode 100644 src/Timeless/ClockInterface.php
diff --git a/composer.json b/composer.json
index 85701f2d..8d1ece1f 100644
--- a/composer.json
+++ b/composer.json
@@ -37,7 +37,8 @@
"recruiterphp/geezer": "^6.0",
"symfony/console": "^7.3",
"symfony/event-dispatcher": "^7.3",
- "ulrichsg/getopt-php": "^4.0"
+ "ulrichsg/getopt-php": "^4.0",
+ "ext-bcmath": "*"
},
"require-dev": {
"dms/phpunit-arraysubset-asserts": "^0.5",
diff --git a/spec/Recruiter/Acceptance/AssignmentTest.php b/spec/Recruiter/Acceptance/AssignmentTest.php
index e173d909..74d9edf7 100644
--- a/spec/Recruiter/Acceptance/AssignmentTest.php
+++ b/spec/Recruiter/Acceptance/AssignmentTest.php
@@ -6,7 +6,7 @@
class AssignmentTest extends BaseAcceptanceTestCase
{
- public function testAJobCanBeAssignedAndExecuted()
+ public function testAJobCanBeAssignedAndExecuted(): void
{
$memoryLimit = new MemoryLimit('64MB');
LazyBones::waitForMs(200, 100)
diff --git a/spec/Recruiter/Acceptance/EnduranceTest.php b/spec/Recruiter/Acceptance/EnduranceTest.php
index b71e3e29..d27e4495 100644
--- a/spec/Recruiter/Acceptance/EnduranceTest.php
+++ b/spec/Recruiter/Acceptance/EnduranceTest.php
@@ -16,7 +16,7 @@ class EnduranceTest extends BaseAcceptanceTestCase
{
use Eris\TestTrait;
- public function setUp(): void
+ protected function setUp(): void
{
parent::setUp();
$this->jobRepository = new Repository($this->recruiterDb);
diff --git a/src/Sink/BlackHole.php b/src/Sink/BlackHole.php
index 154fe15a..4fb20e65 100644
--- a/src/Sink/BlackHole.php
+++ b/src/Sink/BlackHole.php
@@ -15,90 +15,90 @@ public function __destruct()
{
}
- public function __set($name, $value)
+ public function __set(string $name, mixed $value)
{
}
- public function __get($name)
+ public function __get(string $name): self
{
return $this;
}
- public function __isset($name)
+ public function __isset(string $name): bool
{
return false;
}
- public function __unset($name)
+ public function __unset(string $name): void
{
}
- public function __call($name, $arguments)
+ public function __call(string $name, array $arguments)
{
return $this;
}
- public function __toString()
+ public function __toString(): string
{
return '';
}
- public function __invoke()
+ public function __invoke(): self
{
return $this;
}
- public function __clone()
+ public function __clone(): void
{
}
- public static function __callStatic($name, $args)
+ public static function __callStatic(string $name, array $args): self
{
return new self();
}
// Iterator Interface
- public function current()
+ public function current(): self
{
return $this;
}
- public function key()
+ public function key(): self
{
return $this;
}
- public function next()
+ public function next(): void
{
}
- public function rewind()
+ public function rewind(): void
{
}
- public function valid()
+ public function valid(): bool
{
return false;
}
// ArrayAccess Interface
- public function offsetExists($offset)
+ public function offsetExists(mixed $offset): bool
{
return false;
}
- public function offsetGet($offset)
+ public function offsetGet(mixed $offset): self
{
return $this;
}
- public function offsetSet($offset, $value)
+ public function offsetSet(mixed $offset, mixed $value): void
{
}
- public function offsetUnset($offset)
+ public function offsetUnset(mixed $offset): void
{
}
}
diff --git a/src/Timeless/Clock.php b/src/Timeless/Clock.php
index eb8cc7c0..1a5984a5 100644
--- a/src/Timeless/Clock.php
+++ b/src/Timeless/Clock.php
@@ -2,15 +2,15 @@
namespace Timeless;
-class Clock
+class Clock implements ClockInterface
{
- public function stop()
+ public function stop(): ClockInterface
{
return clock(new StoppedClock($this->now()));
}
- public function now()
+ public function now(): Moment
{
- return new Moment(round(microtime(true) * 1000));
+ return new Moment((int) round(microtime(true) * 1000));
}
}
diff --git a/src/Timeless/ClockInterface.php b/src/Timeless/ClockInterface.php
new file mode 100644
index 00000000..7971515e
--- /dev/null
+++ b/src/Timeless/ClockInterface.php
@@ -0,0 +1,8 @@
+ms = intval($ms);
}
public function us(): int
@@ -101,7 +98,7 @@ public function from(Moment $reference): Moment
return $reference->after($this);
}
- public function multiplyBy($multiplier): self
+ public function multiplyBy(int $multiplier): self
{
return new self($this->ms * $multiplier);
}
@@ -111,43 +108,40 @@ public function add(Interval $interval): self
return new self($this->ms + $interval->ms);
}
- public function format($format)
- {
- if (is_string($format)) {
- $availableFormatsTable = [
- 'ms' => ['milliseconds', 'ms', 'ms'],
- 's' => ['seconds', 's', 's'],
- 'm' => ['minutes', 'm', 'm'],
- 'h' => ['hours', 'h', 'h'],
- 'd' => ['days', 'd', 'd'],
- 'w' => ['weeks', 'w', 'w'],
- 'mo' => ['months', 'mo', 'mo'],
- 'y' => ['years', 'y', 'y'],
- 'milliseconds' => ['milliseconds', ' milliseconds', ' millisecond'],
- 'seconds' => ['seconds', ' seconds', ' second'],
- 'minutes' => ['minutes', ' minutes', ' minute'],
- 'hours' => ['hours', ' hours', ' hour'],
- 'days' => ['days', ' days', ' day'],
- 'weeks' => ['weeks', ' weeks', ' week'],
- 'months' => ['months', ' months', ' month'],
- 'years' => ['years', ' years', ' year'],
- ];
- $format = trim($format);
- if (array_key_exists($format, $availableFormatsTable)) {
- $callable = [$this, $availableFormatsTable[$format][0]];
- if (!is_callable($callable)) {
- throw new \RuntimeException("function `{$availableFormatsTable[$format][0]}` does not exists");
- }
-
- $amountOfTime = call_user_func($callable);
- $unitOfTime = $amountOfTime === 1 ?
- $availableFormatsTable[$format][2] :
- $availableFormatsTable[$format][1];
- return sprintf('%d%s', $amountOfTime, $unitOfTime);
+ public function format(string $format): string
+ {
+ $availableFormatsTable = [
+ 'ms' => ['milliseconds', 'ms', 'ms'],
+ 's' => ['seconds', 's', 's'],
+ 'm' => ['minutes', 'm', 'm'],
+ 'h' => ['hours', 'h', 'h'],
+ 'd' => ['days', 'd', 'd'],
+ 'w' => ['weeks', 'w', 'w'],
+ 'mo' => ['months', 'mo', 'mo'],
+ 'y' => ['years', 'y', 'y'],
+ 'milliseconds' => ['milliseconds', ' milliseconds', ' millisecond'],
+ 'seconds' => ['seconds', ' seconds', ' second'],
+ 'minutes' => ['minutes', ' minutes', ' minute'],
+ 'hours' => ['hours', ' hours', ' hour'],
+ 'days' => ['days', ' days', ' day'],
+ 'weeks' => ['weeks', ' weeks', ' week'],
+ 'months' => ['months', ' months', ' month'],
+ 'years' => ['years', ' years', ' year'],
+ ];
+ $format = trim($format);
+ if (array_key_exists($format, $availableFormatsTable)) {
+ $callable = [$this, $availableFormatsTable[$format][0]];
+ if (!is_callable($callable)) {
+ throw new \RuntimeException("function `{$availableFormatsTable[$format][0]}` does not exists");
}
- throw new InvalidIntervalFormat("'{$format}' is not a valid Interval format");
+
+ $amountOfTime = call_user_func($callable);
+ $unitOfTime = $amountOfTime === 1 ?
+ $availableFormatsTable[$format][2] :
+ $availableFormatsTable[$format][1];
+ return sprintf('%d%s', $amountOfTime, $unitOfTime);
}
- throw new InvalidIntervalFormat('You need to use strings');
+ throw new InvalidIntervalFormat("'{$format}' is not a valid Interval format");
}
public function toDateInterval()
@@ -188,7 +182,7 @@ public static function parse($string)
throw new InvalidIntervalFormat('You need to use strings');
}
- public static function fromDateInterval(DateInterval $interval)
+ public static function fromDateInterval(DateInterval $interval): self
{
$startTime = new DateTimeImmutable();
$endTime = $startTime->add($interval);
diff --git a/src/Timeless/Moment.php b/src/Timeless/Moment.php
index 94eeeabe..fd6c96cf 100644
--- a/src/Timeless/Moment.php
+++ b/src/Timeless/Moment.php
@@ -5,76 +5,73 @@
use DateTime;
use DateTimeZone;
-class Moment
+readonly class Moment
{
- private $ms;
-
- public static function fromTimestamp($ts)
+ public static function fromTimestamp(int $ts): self
{
return new self($ts * 1000);
}
- public static function fromDateTime(DateTime $dateTime)
+ public static function fromDateTime(DateTime $dateTime): self
{
- return static::fromTimestamp($dateTime->getTimestamp());
+ return self::fromTimestamp($dateTime->getTimestamp());
}
- public function __construct($ms)
+ public function __construct(private int $ms)
{
- $this->ms = $ms;
}
- public function milliseconds()
+ public function milliseconds(): int
{
return $this->ms;
}
- public function ms()
+ public function ms(): int
{
return $this->ms;
}
- public function seconds()
+ public function seconds(): int
{
return $this->s();
}
- public function s()
+ public function s(): int
{
- return round($this->ms / 1000.0);
+ return (int) round($this->ms / 1000.0);
}
- public function after(Interval $d)
+ public function after(Interval $d): self
{
return new self($this->ms + $d->ms());
}
- public function before(Interval $d)
+ public function before(Interval $d): self
{
return new self($this->ms - $d->ms());
}
- public function isAfter(Moment $m)
+ public function isAfter(Moment $m): bool
{
return $this->ms >= $m->ms();
}
- public function isBefore(Moment $m)
+ public function isBefore(Moment $m): bool
{
return $this->ms <= $m->ms();
}
- public function toSecondPrecision()
+ public function toSecondPrecision(): Moment
{
return new self($this->s() * 1000);
}
- public function format()
+ public function format(): string
{
- return (new DateTime('@' . $this->s(), new DateTimeZone('UTC')))->format(DateTime::RFC3339);
+ return new DateTime('@' . $this->s(), new DateTimeZone('UTC'))->format(DateTime::RFC3339);
}
- public function toDateTime()
+ public function toDateTime(): DateTime
{
return new DateTime('@' . $this->s(), new DateTimeZone('UTC'));
}
diff --git a/src/Timeless/StoppedClock.php b/src/Timeless/StoppedClock.php
index d653dbf9..2e10ac94 100644
--- a/src/Timeless/StoppedClock.php
+++ b/src/Timeless/StoppedClock.php
@@ -2,26 +2,23 @@
namespace Timeless;
-class StoppedClock
+class StoppedClock implements ClockInterface
{
- private $now;
-
- public function __construct(Moment $now)
+ public function __construct(private Moment $now)
{
- $this->now = $now;
}
- public function now()
+ public function now(): Moment
{
return $this->now;
}
- public function driftForwardBySeconds($seconds)
+ public function driftForwardBySeconds(int $seconds): void
{
$this->now = $this->now->after(seconds($seconds));
}
- public function start()
+ public function start(): ClockInterface
{
return clock(new Clock());
}
diff --git a/src/Timeless/functions.php b/src/Timeless/functions.php
index 26b0a0ab..ac986332 100644
--- a/src/Timeless/functions.php
+++ b/src/Timeless/functions.php
@@ -2,9 +2,10 @@
namespace Timeless;
-function clock($clock = null)
+function clock(?ClockInterface $clock = null): ClockInterface
{
global $__2852bec4cda046fca0e5e21dc007935c;
+ /** @var ClockInterface $__2852bec4cda046fca0e5e21dc007935c */
$__2852bec4cda046fca0e5e21dc007935c =
$clock ?: (
$__2852bec4cda046fca0e5e21dc007935c ?: new Clock()
@@ -12,92 +13,92 @@ function clock($clock = null)
return $__2852bec4cda046fca0e5e21dc007935c;
}
-function now()
+function now(): Moment
{
return clock()->now();
}
-function millisecond($numberOf)
+function millisecond(int $numberOf): Interval
{
return milliseconds($numberOf);
}
-function milliseconds($numberOf)
+function milliseconds(int $numberOf): Interval
{
return new Interval($numberOf);
}
-function second($numberOf)
+function second(int $numberOf): Interval
{
return seconds($numberOf);
}
-function seconds($numberOf)
+function seconds(int $numberOf): Interval
{
return new Interval($numberOf * Interval::MILLISECONDS_IN_SECONDS);
}
-function minute($numberOf)
+function minute(int $numberOf): Interval
{
return minutes($numberOf);
}
-function minutes($numberOf)
+function minutes(int $numberOf): Interval
{
return new Interval($numberOf * Interval::MILLISECONDS_IN_MINUTES);
}
-function hour($numberOf)
+function hour(int $numberOf): Interval
{
return hours($numberOf);
}
-function hours($numberOf)
+function hours(int $numberOf): Interval
{
return new Interval($numberOf * Interval::MILLISECONDS_IN_HOURS);
}
-function day($numberOf)
+function day(int $numberOf): Interval
{
return days($numberOf);
}
-function days($numberOf)
+function days(int $numberOf): Interval
{
return new Interval($numberOf * Interval::MILLISECONDS_IN_DAYS);
}
-function week($numberOf)
+function week(int $numberOf): Interval
{
return weeks($numberOf);
}
-function weeks($numberOf)
+function weeks(int $numberOf): Interval
{
return new Interval($numberOf * Interval::MILLISECONDS_IN_WEEKS);
}
-function month($numberOf)
+function month(int $numberOf): Interval
{
return months($numberOf);
}
-function months($numberOf)
+function months(int $numberOf): Interval
{
return new Interval($numberOf * Interval::MILLISECONDS_IN_MONTHS);
}
-function year($numberOf)
+function year(int $numberOf): Interval
{
return years($numberOf);
}
-function years($numberOf)
+function years(int $numberOf): Interval
{
return new Interval($numberOf * Interval::MILLISECONDS_IN_YEARS);
}
-function fromDateInterval(\DateInterval $interval)
+function fromDateInterval(\DateInterval $interval): Interval
{
$seconds = (string) $interval->s;
if ($interval->i) {
From 1283cca3e177032ad84c1018bb90ecdec5a61629 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 02:01:18 +0200
Subject: [PATCH 06/59] Lower phpstan
---
phpstan.neon | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/phpstan.neon b/phpstan.neon
index e4015b46..dc25ee1c 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,5 +1,5 @@
parameters:
- level: max
+ level: 0
paths:
- src
- spec
From d23ce9509125bc6d4e5685f799a335de6d93f433 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 02:12:32 +0200
Subject: [PATCH 07/59] Add more types
---
spec/Recruiter/TaggableWorkableTest.php | 2 +-
src/Recruiter/Workable.php | 12 +++---------
src/Recruiter/Workable/FactoryMethodCommand.php | 4 ++--
src/Recruiter/Workable/LazyBones.php | 16 ++++++----------
src/Recruiter/Workable/ShellCommand.php | 2 +-
src/Recruiter/WorkableBehaviour.php | 11 ++++-------
6 files changed, 17 insertions(+), 30 deletions(-)
diff --git a/spec/Recruiter/TaggableWorkableTest.php b/spec/Recruiter/TaggableWorkableTest.php
index 5479a37a..c0f04a81 100644
--- a/spec/Recruiter/TaggableWorkableTest.php
+++ b/spec/Recruiter/TaggableWorkableTest.php
@@ -110,7 +110,7 @@ public function export()
return ['tags' => $this->tags];
}
- public static function import($parameters)
+ public static function import(array $parameters)
{
return new self($parameters['tags']);
}
diff --git a/src/Recruiter/Workable.php b/src/Recruiter/Workable.php
index aefa2471..4a9733df 100644
--- a/src/Recruiter/Workable.php
+++ b/src/Recruiter/Workable.php
@@ -6,26 +6,20 @@ interface Workable
{
/**
* Turn this `Recruiter\Workable` instance into a `Recruiter\Job` instance
- *
- * @param Recruiter $recruiter
- *
- * @return JobToSchedule
*/
- public function asJobOf(Recruiter $recruiter);
+ public function asJobOf(Recruiter $recruiter): JobToSchedule;
/**
* Export parameters that need to be persisted
*
* @return array
*/
- public function export();
+ public function export(): array;
/**
* Import an array of parameters as a Workable instance
*
* @param array $parameters Previously exported parameters
- *
- * @return Workable
*/
- public static function import($parameters);
+ public static function import(array $parameters): static;
}
diff --git a/src/Recruiter/Workable/FactoryMethodCommand.php b/src/Recruiter/Workable/FactoryMethodCommand.php
index 3951e9e4..6f7c33a0 100644
--- a/src/Recruiter/Workable/FactoryMethodCommand.php
+++ b/src/Recruiter/Workable/FactoryMethodCommand.php
@@ -104,8 +104,8 @@ public function export()
];
}
- public static function import($document)
+ public static function import(array $parameters)
{
- return new self($document['steps']);
+ return new self($parameters['steps']);
}
}
diff --git a/src/Recruiter/Workable/LazyBones.php b/src/Recruiter/Workable/LazyBones.php
index d2612f7d..cff5c372 100644
--- a/src/Recruiter/Workable/LazyBones.php
+++ b/src/Recruiter/Workable/LazyBones.php
@@ -9,31 +9,27 @@ class LazyBones implements Workable
{
use WorkableBehaviour;
- private $usToSleep;
- private $usOfDelta;
- public static function waitFor($timeInSeconds, $deltaInSeconds = 0)
+ public static function waitFor(int $timeInSeconds, int $deltaInSeconds = 0): self
{
return new self($timeInSeconds * 1000000, $deltaInSeconds * 1000000);
}
- public static function waitForMs($timeInMs, $deltaInMs = 0)
+ public static function waitForMs($timeInMs, $deltaInMs = 0): self
{
return new self($timeInMs * 1000, $deltaInMs * 1000);
}
- public function __construct($usToSleep = 1, $usOfDelta = 0)
+ public function __construct(private readonly int $usToSleep = 1, private readonly int $usOfDelta = 0)
{
- $this->usToSleep = $usToSleep;
- $this->usOfDelta = $usOfDelta;
}
- public function execute()
+ public function execute(): void
{
usleep($this->usToSleep + (rand(intval(-$this->usOfDelta), $this->usOfDelta)));
}
- public function export()
+ public function export(): array
{
return [
'us_to_sleep' => $this->usToSleep,
@@ -41,7 +37,7 @@ public function export()
];
}
- public static function import($parameters)
+ public static function import(array $parameters): static
{
return new self(
$parameters['us_to_sleep'],
diff --git a/src/Recruiter/Workable/ShellCommand.php b/src/Recruiter/Workable/ShellCommand.php
index 62aea315..c3531b54 100644
--- a/src/Recruiter/Workable/ShellCommand.php
+++ b/src/Recruiter/Workable/ShellCommand.php
@@ -37,7 +37,7 @@ public function export()
return ['command' => $this->commandLine];
}
- public static function import($parameters)
+ public static function import(array $parameters)
{
return new self($parameters['command']);
}
diff --git a/src/Recruiter/WorkableBehaviour.php b/src/Recruiter/WorkableBehaviour.php
index 8cfbc88b..2446863d 100644
--- a/src/Recruiter/WorkableBehaviour.php
+++ b/src/Recruiter/WorkableBehaviour.php
@@ -6,14 +6,11 @@
trait WorkableBehaviour
{
- protected $parameters;
-
- public function __construct($parameters = [])
+ public final function __construct(protected array $parameters = [])
{
- $this->parameters = $parameters;
}
- public function asJobOf(Recruiter $recruiter)
+ public function asJobOf(Recruiter $recruiter): JobToSchedule
{
return $recruiter->jobOf($this);
}
@@ -23,12 +20,12 @@ public function execute()
throw new Exception('Workable::execute() need to be implemented');
}
- public function export()
+ public function export(): array
{
return $this->parameters;
}
- public static function import($parameters)
+ public static function import(array $parameters): static
{
return new static($parameters);
}
From 6c7f127b60d7d6e55a2681722562c9f7886a1b03 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 02:32:43 +0200
Subject: [PATCH 08/59] Fix Timeless signature
---
src/Timeless/Clock.php | 5 +++++
src/Timeless/ClockInterface.php | 4 ++++
src/Timeless/StoppedClock.php | 5 +++++
3 files changed, 14 insertions(+)
diff --git a/src/Timeless/Clock.php b/src/Timeless/Clock.php
index 1a5984a5..d046af0f 100644
--- a/src/Timeless/Clock.php
+++ b/src/Timeless/Clock.php
@@ -4,6 +4,11 @@
class Clock implements ClockInterface
{
+ public function start(): ClockInterface
+ {
+ return clock($this);
+ }
+
public function stop(): ClockInterface
{
return clock(new StoppedClock($this->now()));
diff --git a/src/Timeless/ClockInterface.php b/src/Timeless/ClockInterface.php
index 7971515e..c01f2dd3 100644
--- a/src/Timeless/ClockInterface.php
+++ b/src/Timeless/ClockInterface.php
@@ -5,4 +5,8 @@
interface ClockInterface
{
public function now(): Moment;
+
+ public function start(): ClockInterface;
+
+ public function stop(): ClockInterface;
}
\ No newline at end of file
diff --git a/src/Timeless/StoppedClock.php b/src/Timeless/StoppedClock.php
index 2e10ac94..77392ab4 100644
--- a/src/Timeless/StoppedClock.php
+++ b/src/Timeless/StoppedClock.php
@@ -22,4 +22,9 @@ public function start(): ClockInterface
{
return clock(new Clock());
}
+
+ public function stop(): ClockInterface
+ {
+ return clock($this);
+ }
}
From 5f1f4775cc543de8cc8599c4c55bff511ce05a0f Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 02:33:49 +0200
Subject: [PATCH 09/59] Use array_any instead
---
src/Recruiter/RetryPolicy/RetriableExceptionFilter.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php b/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
index b0225307..10a5913b 100644
--- a/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
+++ b/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
@@ -78,7 +78,7 @@ private function ensureAreAllExceptions($exceptions)
private function isExceptionRetriable($exception)
{
if (!is_null($exception) && is_object($exception)) {
- return \Recruiter\array_some(
+ return array_any(
$this->retriableExceptions,
function ($retriableExceptionType) use ($exception) {
return ($exception instanceof $retriableExceptionType);
From 41dfc8a9b18f0d5cac85e67ddef7bca77fe7f00c Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 02:42:00 +0200
Subject: [PATCH 10/59] Make setUp and tearDown protected
---
spec/Recruiter/Acceptance/HooksTest.php | 2 +-
spec/Recruiter/Acceptance/WorkerRepositoryTest.php | 2 +-
spec/Recruiter/CleanerTest.php | 4 ++--
...sAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php | 2 +-
spec/Recruiter/Job/RepositoryTest.php | 2 +-
spec/Recruiter/JobCallCustomMethodOnWorkableTest.php | 2 +-
spec/Recruiter/JobSendEventsToWorkableTest.php | 2 +-
.../Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php | 2 +-
spec/Recruiter/JobTest.php | 2 +-
spec/Recruiter/JobToBePassedRetryStatisticsTest.php | 2 +-
spec/Recruiter/JobToScheduleTest.php | 4 ++--
spec/Recruiter/PickAvailableWorkersTest.php | 2 +-
spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php | 2 +-
spec/Recruiter/RetryPolicy/TimeTableTest.php | 2 +-
spec/Recruiter/TaggableWorkableTest.php | 2 +-
spec/Recruiter/WaitStrategyTest.php | 2 +-
spec/Recruiter/WorkerProcessTest.php | 2 +-
17 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/spec/Recruiter/Acceptance/HooksTest.php b/spec/Recruiter/Acceptance/HooksTest.php
index e66b9899..6003f6a1 100644
--- a/spec/Recruiter/Acceptance/HooksTest.php
+++ b/spec/Recruiter/Acceptance/HooksTest.php
@@ -9,7 +9,7 @@
class HooksTest extends BaseAcceptanceTestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->memoryLimit = new MemoryLimit('64MB');
parent::setUp();
diff --git a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
index f1918982..c8c1638f 100644
--- a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
+++ b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
@@ -7,7 +7,7 @@
class WorkerRepositoryTest extends BaseAcceptanceTestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
parent::setUp();
$this->repository = new Repository(
diff --git a/spec/Recruiter/CleanerTest.php b/spec/Recruiter/CleanerTest.php
index a1a70f64..59123781 100644
--- a/spec/Recruiter/CleanerTest.php
+++ b/spec/Recruiter/CleanerTest.php
@@ -8,7 +8,7 @@
class CleanerTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->clock = T\clock()->stop();
$this->now = $this->clock->now();
@@ -23,7 +23,7 @@ public function setUp(): void
$this->interval = Interval::parse('10s');
}
- public function tearDown(): void
+ protected function tearDown(): void
{
T\clock()->start();
}
diff --git a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
index aa786638..84f8960e 100644
--- a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
+++ b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
@@ -7,7 +7,7 @@
class FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->repository = $this
->getMockBuilder('Recruiter\Job\Repository')
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 0254b20f..7c0e7e58 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -29,7 +29,7 @@ protected function setUp(): void
$this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
}
- public function tearDown(): void
+ protected function tearDown(): void
{
T\clock()->start();
}
diff --git a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
index 1c3cb65e..9217b2dc 100644
--- a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
+++ b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
@@ -7,7 +7,7 @@
class JobCallCustomMethodOnWorkableTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->workable = $this
->getMockBuilder('Recruiter\Workable')
diff --git a/spec/Recruiter/JobSendEventsToWorkableTest.php b/spec/Recruiter/JobSendEventsToWorkableTest.php
index ab72e71e..240a2ccb 100644
--- a/spec/Recruiter/JobSendEventsToWorkableTest.php
+++ b/spec/Recruiter/JobSendEventsToWorkableTest.php
@@ -8,7 +8,7 @@
class JobSendEventsToWorkableTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->repository = $this
->getMockBuilder('Recruiter\Job\Repository')
diff --git a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
index 4bafeda3..a8a67abd 100644
--- a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
+++ b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
@@ -8,7 +8,7 @@
class JobTakeRetryPolicyFromRetriableWorkableTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->repository = $this
->getMockBuilder('Recruiter\Job\Repository')
diff --git a/spec/Recruiter/JobTest.php b/spec/Recruiter/JobTest.php
index 6df774bf..e9150b62 100644
--- a/spec/Recruiter/JobTest.php
+++ b/spec/Recruiter/JobTest.php
@@ -8,7 +8,7 @@
class JobTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->repository = $this
->getMockBuilder('Recruiter\Job\Repository')
diff --git a/spec/Recruiter/JobToBePassedRetryStatisticsTest.php b/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
index cce51d76..ce95ef0a 100644
--- a/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
+++ b/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
@@ -8,7 +8,7 @@
class JobToBePassedRetryStatisticsTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->repository = $this
->getMockBuilder('Recruiter\Job\Repository')
diff --git a/spec/Recruiter/JobToScheduleTest.php b/spec/Recruiter/JobToScheduleTest.php
index 5de7f8f7..1d1d72e5 100644
--- a/spec/Recruiter/JobToScheduleTest.php
+++ b/spec/Recruiter/JobToScheduleTest.php
@@ -8,7 +8,7 @@
class JobToScheduleTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->clock = T\clock()->stop();
$this->job = $this
@@ -17,7 +17,7 @@ public function setUp(): void
->getMock();
}
- public function tearDown(): void
+ protected function tearDown(): void
{
$this->clock->start();
}
diff --git a/spec/Recruiter/PickAvailableWorkersTest.php b/spec/Recruiter/PickAvailableWorkersTest.php
index 5ca538a4..60ff3db7 100644
--- a/spec/Recruiter/PickAvailableWorkersTest.php
+++ b/spec/Recruiter/PickAvailableWorkersTest.php
@@ -8,7 +8,7 @@
class PickAvailableWorkersTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->repository = $this
->getMockBuilder('MongoDB\Collection')
diff --git a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
index 3d2354b6..f753f0ce 100644
--- a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
+++ b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
@@ -8,7 +8,7 @@
class RetriableExceptionFilterTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->filteredRetryPolicy = $this->createMock('Recruiter\RetryPolicy');
}
diff --git a/spec/Recruiter/RetryPolicy/TimeTableTest.php b/spec/Recruiter/RetryPolicy/TimeTableTest.php
index d6c3fbf1..2e46f143 100644
--- a/spec/Recruiter/RetryPolicy/TimeTableTest.php
+++ b/spec/Recruiter/RetryPolicy/TimeTableTest.php
@@ -10,7 +10,7 @@ class TimeTableTest extends TestCase
{
private $scheduler;
- public function setUp(): void
+ protected function setUp(): void
{
$this->scheduler = new TimeTable([
'5 minutes ago' => '1 minute',
diff --git a/spec/Recruiter/TaggableWorkableTest.php b/spec/Recruiter/TaggableWorkableTest.php
index c0f04a81..33bb37c1 100644
--- a/spec/Recruiter/TaggableWorkableTest.php
+++ b/spec/Recruiter/TaggableWorkableTest.php
@@ -8,7 +8,7 @@
class TaggableWorkableTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->repository = $this
->getMockBuilder('Recruiter\Job\Repository')
diff --git a/spec/Recruiter/WaitStrategyTest.php b/spec/Recruiter/WaitStrategyTest.php
index e6a305d4..7cdf3fbd 100644
--- a/spec/Recruiter/WaitStrategyTest.php
+++ b/spec/Recruiter/WaitStrategyTest.php
@@ -7,7 +7,7 @@
class WaitStrategyTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->waited = 0;
$this->howToWait = function($microseconds): void {
diff --git a/spec/Recruiter/WorkerProcessTest.php b/spec/Recruiter/WorkerProcessTest.php
index 8ef203fa..b808410b 100644
--- a/spec/Recruiter/WorkerProcessTest.php
+++ b/spec/Recruiter/WorkerProcessTest.php
@@ -6,7 +6,7 @@
class WorkerProcessTest extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
$this->pid = 4242;
From c422d04225381b1ed76d49b3272ff9b5609e7b1f Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:08:32 +0200
Subject: [PATCH 11/59] Fix more types
---
.../Acceptance/BaseAcceptanceTestCase.php | 2 ++
spec/Recruiter/Acceptance/EnduranceTest.php | 3 +++
spec/Recruiter/Acceptance/HooksTest.php | 2 ++
.../RepeatableJobsAreScheduledTest.php | 4 ++--
.../Acceptance/WorkerRepositoryTest.php | 1 +
spec/Recruiter/CleanerTest.php | 9 ++++++++
...rkableImplementsFinalizerInterfaceTest.php | 15 +++++++++----
spec/Recruiter/Job/RepositoryTest.php | 7 +++++++
.../JobCallCustomMethodOnWorkableTest.php | 10 +++++++--
.../Recruiter/JobSendEventsToWorkableTest.php | 12 +++++++----
...keRetryPolicyFromRetriableWorkableTest.php | 21 +++++++++++++------
spec/Recruiter/JobTest.php | 6 +++++-
.../JobToBePassedRetryStatisticsTest.php | 14 ++++++++++---
spec/Recruiter/JobToScheduleTest.php | 7 ++++++-
spec/Recruiter/PickAvailableWorkersTest.php | 7 ++++++-
.../RetriableExceptionFilterTest.php | 15 +++++++++----
spec/Recruiter/TaggableWorkableTest.php | 6 +++++-
spec/Recruiter/WaitStrategyTest.php | 7 ++++++-
spec/Recruiter/WorkerProcessTest.php | 13 +++++++++---
19 files changed, 128 insertions(+), 33 deletions(-)
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index 50785542..15d1ff4a 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -22,6 +22,8 @@ abstract class BaseAcceptanceTestCase extends TestCase
protected Collection $archived;
protected Collection $roster;
protected Collection $schedulers;
+ protected array $files;
+ protected int $jobs;
private ?array $processRecruiter;
private ?array $processCleaner;
private array $processWorkers;
diff --git a/spec/Recruiter/Acceptance/EnduranceTest.php b/spec/Recruiter/Acceptance/EnduranceTest.php
index d27e4495..66d74e72 100644
--- a/spec/Recruiter/Acceptance/EnduranceTest.php
+++ b/spec/Recruiter/Acceptance/EnduranceTest.php
@@ -16,6 +16,9 @@ class EnduranceTest extends BaseAcceptanceTestCase
{
use Eris\TestTrait;
+ private Repository $jobRepository;
+ private string $actionLog;
+
protected function setUp(): void
{
parent::setUp();
diff --git a/spec/Recruiter/Acceptance/HooksTest.php b/spec/Recruiter/Acceptance/HooksTest.php
index 6003f6a1..68fed4bd 100644
--- a/spec/Recruiter/Acceptance/HooksTest.php
+++ b/spec/Recruiter/Acceptance/HooksTest.php
@@ -9,6 +9,8 @@
class HooksTest extends BaseAcceptanceTestCase
{
+ private MemoryLimit $memoryLimit;
+ private array $events;
protected function setUp(): void
{
$this->memoryLimit = new MemoryLimit('64MB');
diff --git a/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php b/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
index abce5a0c..a9c6ab34 100644
--- a/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
+++ b/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
@@ -183,8 +183,8 @@ private function fetchSchedulers()
class FixedSchedulePolicy implements SchedulePolicy
{
- private $timestamp;
- private $index;
+ private array $timestamps;
+ private int $index;
public function __construct($timestamps, $index = 0)
{
diff --git a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
index c8c1638f..85634cbd 100644
--- a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
+++ b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
@@ -7,6 +7,7 @@
class WorkerRepositoryTest extends BaseAcceptanceTestCase
{
+ private Repository $repository;
protected function setUp(): void
{
parent::setUp();
diff --git a/spec/Recruiter/CleanerTest.php b/spec/Recruiter/CleanerTest.php
index 59123781..295875a0 100644
--- a/spec/Recruiter/CleanerTest.php
+++ b/spec/Recruiter/CleanerTest.php
@@ -3,11 +3,20 @@
namespace Recruiter;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
use Timeless\Interval;
+use Timeless\Clock;
+use Timeless\Moment;
use Timeless as T;
class CleanerTest extends TestCase
{
+ private T\ClockInterface $clock;
+ private Moment $now;
+ private MockObject $jobRepository;
+ private Cleaner $cleaner;
+ private Interval $interval;
+
protected function setUp(): void
{
$this->clock = T\clock()->stop();
diff --git a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
index 84f8960e..40c86b12 100644
--- a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
+++ b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
@@ -4,19 +4,26 @@
use Exception;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+use Recruiter\Job\Repository;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest extends TestCase
{
+ private MockObject&Repository $repository;
+ private EventDispatcherInterface $dispatcher;
+
+ /**
+ * @throws \PHPUnit\Framework\MockObject\Exception
+ */
protected function setUp(): void
{
$this->repository = $this
- ->getMockBuilder('Recruiter\Job\Repository')
+ ->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
- $this->dispatcher = $this->createMock(
- 'Symfony\Component\EventDispatcher\EventDispatcherInterface'
- );
+ $this->dispatcher = $this->createMock(EventDispatcherInterface::class);
}
public function testFinalizableFailureMethodsAreCalledWhenJobFails()
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 7c0e7e58..34579406 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -2,6 +2,7 @@
namespace Recruiter\Job;
use MongoDB\BSON\ObjectId;
+use MongoDB\Database;
use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
@@ -11,11 +12,17 @@
use Recruiter\JobToSchedule;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Timeless as T;
+use Timeless\Clock;
use Timeless\Interval;
use Timeless\Moment;
class RepositoryTest extends TestCase
{
+ private Database $recruiterDb;
+ private Repository $repository;
+ private T\ClockInterface $clock;
+ private EventDispatcherInterface $eventDispatcher;
+
/**
* @throws Exception
*/
diff --git a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
index 9217b2dc..580d9c9b 100644
--- a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
+++ b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
@@ -4,18 +4,24 @@
use Exception;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+use Recruiter\Job\Repository;
class JobCallCustomMethodOnWorkableTest extends TestCase
{
+ private MockObject&Workable $workable;
+ private MockObject&Repository $repository;
+ private Job $job;
+
protected function setUp(): void
{
$this->workable = $this
- ->getMockBuilder('Recruiter\Workable')
+ ->getMockBuilder(Workable::class)
->setMethods(['export', 'import', 'asJobOf', 'send'])
->getMock();
$this->repository = $this
- ->getMockBuilder('Recruiter\Job\Repository')
+ ->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
diff --git a/spec/Recruiter/JobSendEventsToWorkableTest.php b/spec/Recruiter/JobSendEventsToWorkableTest.php
index 240a2ccb..cf72836f 100644
--- a/spec/Recruiter/JobSendEventsToWorkableTest.php
+++ b/spec/Recruiter/JobSendEventsToWorkableTest.php
@@ -3,21 +3,25 @@
namespace Recruiter;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
use Recruiter\Job\Event;
use Recruiter\Job\EventListener;
+use Recruiter\Job\Repository;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class JobSendEventsToWorkableTest extends TestCase
{
+ private MockObject&Repository $repository;
+ private MockObject&EventDispatcherInterface $dispatcher;
+
protected function setUp(): void
{
$this->repository = $this
- ->getMockBuilder('Recruiter\Job\Repository')
+ ->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
- $this->dispatcher = $this->createMock(
- 'Symfony\Component\EventDispatcher\EventDispatcherInterface'
- );
+ $this->dispatcher = $this->createMock(EventDispatcherInterface::class);
}
public function testTakeRetryPolicyFromRetriableInstance()
diff --git a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
index a8a67abd..84f89dd6 100644
--- a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
+++ b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
@@ -2,26 +2,36 @@
namespace Recruiter;
+use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+use Recruiter\Job\Repository;
+use Recruiter\RetryPolicy\BaseRetryPolicy;
use Timeless as T;
use Recruiter\RetryPolicy;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class JobTakeRetryPolicyFromRetriableWorkableTest extends TestCase
{
+ private MockObject&Repository $repository;
+ private MockObject&EventDispatcherInterface $eventDispatcher;
+
protected function setUp(): void
{
$this->repository = $this
- ->getMockBuilder('Recruiter\Job\Repository')
+ ->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
- $this->eventDispatcher = $this
- ->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+ $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
}
+ /**
+ * @throws Exception
+ */
public function testTakeRetryPolicyFromRetriableInstance()
{
- $retryPolicy = $this->createMock('Recruiter\RetryPolicy\BaseRetryPolicy');
+ $retryPolicy = $this->createMock(BaseRetryPolicy::class);
$retryPolicy->expects($this->once())->method('schedule');
$workable = new WorkableThatIsAlsoRetriable($retryPolicy);
@@ -35,9 +45,8 @@ class WorkableThatIsAlsoRetriable implements Workable, Retriable
{
use WorkableBehaviour;
- public function __construct(RetryPolicy $retryWithPolicy)
+ public function __construct(private readonly RetryPolicy $retryWithPolicy)
{
- $this->retryWithPolicy = $retryWithPolicy;
}
public function retryWithPolicy(): RetryPolicy
diff --git a/spec/Recruiter/JobTest.php b/spec/Recruiter/JobTest.php
index e9150b62..88334c7f 100644
--- a/spec/Recruiter/JobTest.php
+++ b/spec/Recruiter/JobTest.php
@@ -2,16 +2,20 @@
namespace Recruiter;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+use Recruiter\Job\Repository;
use Recruiter\Workable\AlwaysFail;
use RuntimeException;
use Recruiter\Infrastructure\Memory\MemoryLimit;
class JobTest extends TestCase
{
+ private MockObject&Repository $repository;
+
protected function setUp(): void
{
$this->repository = $this
- ->getMockBuilder('Recruiter\Job\Repository')
+ ->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
}
diff --git a/spec/Recruiter/JobToBePassedRetryStatisticsTest.php b/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
index ce95ef0a..e54cf7a2 100644
--- a/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
+++ b/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
@@ -2,26 +2,34 @@
namespace Recruiter;
+use PHPUnit\Framework\MockObject\Exception;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
-use Timeless as T;
+use Recruiter\Job\Repository;
use Recruiter\RetryPolicy\DoNotDoItAgain;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class JobToBePassedRetryStatisticsTest extends TestCase
{
+ private MockObject&Repository $repository;
+
protected function setUp(): void
{
$this->repository = $this
- ->getMockBuilder('Recruiter\Job\Repository')
+ ->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
}
+ /**
+ * @throws Exception
+ */
public function testTakeRetryPolicyFromRetriableInstance()
{
$workable = new WorkableThatUsesRetryStatistics();
$job = Job::around($workable, $this->repository);
- $job->execute($this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'));
+ $job->execute($this->createMock(EventDispatcherInterface::class));
$this->assertTrue($job->done(), "Job requiring retry statistics was not executed correctly: " . var_export($job->export(), true));
}
}
diff --git a/spec/Recruiter/JobToScheduleTest.php b/spec/Recruiter/JobToScheduleTest.php
index 1d1d72e5..36fc6ff5 100644
--- a/spec/Recruiter/JobToScheduleTest.php
+++ b/spec/Recruiter/JobToScheduleTest.php
@@ -3,16 +3,21 @@
namespace Recruiter;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
use Timeless as T;
+use Timeless\Clock;
use Recruiter\RetryPolicy;
class JobToScheduleTest extends TestCase
{
+ private T\ClockInterface $clock;
+ private MockObject&Job $job;
+
protected function setUp(): void
{
$this->clock = T\clock()->stop();
$this->job = $this
- ->getMockBuilder('Recruiter\Job')
+ ->getMockBuilder(Job::class)
->disableOriginalConstructor()
->getMock();
}
diff --git a/spec/Recruiter/PickAvailableWorkersTest.php b/spec/Recruiter/PickAvailableWorkersTest.php
index 60ff3db7..7c54d84f 100644
--- a/spec/Recruiter/PickAvailableWorkersTest.php
+++ b/spec/Recruiter/PickAvailableWorkersTest.php
@@ -4,14 +4,19 @@
use ArrayIterator;
use MongoDB\BSON\ObjectId;
+use MongoDB\Collection;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
class PickAvailableWorkersTest extends TestCase
{
+ private MockObject&Collection $repository;
+ private int $workersPerUnit;
+
protected function setUp(): void
{
$this->repository = $this
- ->getMockBuilder('MongoDB\Collection')
+ ->getMockBuilder(Collection::class)
->disableOriginalConstructor()
->getMock();
diff --git a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
index f753f0ce..bffbd9e8 100644
--- a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
+++ b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
@@ -5,17 +5,24 @@
use Exception;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+use Recruiter\RetryPolicy;
class RetriableExceptionFilterTest extends TestCase
{
+ private MockObject&RetryPolicy $filteredRetryPolicy;
+
+ /**
+ * @throws \PHPUnit\Framework\MockObject\Exception
+ */
protected function setUp(): void
{
- $this->filteredRetryPolicy = $this->createMock('Recruiter\RetryPolicy');
+ $this->filteredRetryPolicy = $this->createMock(RetryPolicy::class);
}
public function testCallScheduleOnRetriableException()
{
- $exception = $this->createMock('Exception');
+ $exception = $this->createMock(Exception::class);
$classOfException = get_class($exception);
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
@@ -28,7 +35,7 @@ public function testCallScheduleOnRetriableException()
public function testDoNotCallScheduleOnNonRetriableException()
{
- $exception = $this->createMock('Exception');
+ $exception = $this->createMock(Exception::class);
$classOfException = get_class($exception);
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
@@ -41,7 +48,7 @@ public function testDoNotCallScheduleOnNonRetriableException()
public function testWhenExceptionIsNotRetriableThenArchiveTheJob()
{
- $exception = $this->createMock('Exception');
+ $exception = $this->createMock(Exception::class);
$classOfException = get_class($exception);
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
diff --git a/spec/Recruiter/TaggableWorkableTest.php b/spec/Recruiter/TaggableWorkableTest.php
index 33bb37c1..949d52a3 100644
--- a/spec/Recruiter/TaggableWorkableTest.php
+++ b/spec/Recruiter/TaggableWorkableTest.php
@@ -3,15 +3,19 @@
namespace Recruiter;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+use Recruiter\Job\Repository;
use Timeless as T;
use Recruiter\Taggable;
class TaggableWorkableTest extends TestCase
{
+ private MockObject&Repository $repository;
+
protected function setUp(): void
{
$this->repository = $this
- ->getMockBuilder('Recruiter\Job\Repository')
+ ->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
}
diff --git a/spec/Recruiter/WaitStrategyTest.php b/spec/Recruiter/WaitStrategyTest.php
index 7cdf3fbd..909aa0a9 100644
--- a/spec/Recruiter/WaitStrategyTest.php
+++ b/spec/Recruiter/WaitStrategyTest.php
@@ -7,9 +7,14 @@
class WaitStrategyTest extends TestCase
{
+ private T\Interval $waited;
+ private \Closure $howToWait;
+ private T\Interval $timeToWaitAtLeast;
+ private T\Interval $timeToWaitAtMost;
+
protected function setUp(): void
{
- $this->waited = 0;
+ $this->waited = T\milliseconds(0);
$this->howToWait = function($microseconds): void {
$this->waited = T\milliseconds($microseconds/1000);
};
diff --git a/spec/Recruiter/WorkerProcessTest.php b/spec/Recruiter/WorkerProcessTest.php
index b808410b..df9c1b30 100644
--- a/spec/Recruiter/WorkerProcessTest.php
+++ b/spec/Recruiter/WorkerProcessTest.php
@@ -3,14 +3,21 @@
namespace Recruiter;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+use Recruiter\Worker\Process;
+use Recruiter\Worker\Repository;
+use Sink\BlackHole;
class WorkerProcessTest extends TestCase
{
+ private int $pid;
+ private MockObject&Repository $repository;
+
protected function setUp(): void
{
$this->pid = 4242;
- $this->repository = $this->getMockBuilder('Recruiter\Worker\Repository')
+ $this->repository = $this->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
}
@@ -18,13 +25,13 @@ protected function setUp(): void
public function testIfNotAliveWhenIsNotAliveReturnsItself()
{
$process = $this->givenWorkerProcessDead();
- $this->assertInstanceOf('Recruiter\Worker\Process', $process->ifDead());
+ $this->assertInstanceOf(Process::class, $process->ifDead());
}
public function testIfNotAliveWhenIsAliveReturnsBlackHole()
{
$process = $this->givenWorkerProcessAlive();
- $this->assertInstanceOf('Sink\BlackHole', $process->ifDead());
+ $this->assertInstanceOf(BlackHole::class, $process->ifDead());
}
public function testRetireWorkerIfNotAlive()
From 9a603c482c45a8fe9d6dc4dbd280e74bc526a0e1 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:19:24 +0200
Subject: [PATCH 12/59] Fix further type hints
---
spec/Recruiter/Job/RepositoryTest.php | 4 +--
.../Recruiter/JobSendEventsToWorkableTest.php | 13 +++++----
spec/Recruiter/JobTest.php | 2 +-
spec/Recruiter/TaggableWorkableTest.php | 4 +--
src/Recruiter/Cleaner.php | 2 +-
src/Recruiter/Command/RecruiterJobCommand.php | 18 +++++-------
.../Command/Bko/AnalyticsCommand.php | 24 ++++-----------
.../Command/Bko/JobRecoverCommand.php | 29 ++++---------------
.../Command/Bko/RemoveSchedulerCommand.php | 6 ++--
src/Recruiter/Job/Repository.php | 8 ++---
src/Recruiter/Recruiter.php | 4 +--
11 files changed, 43 insertions(+), 71 deletions(-)
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 34579406..772da5d4 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -238,7 +238,7 @@ public function testGetRecentJobsWithManyAttempts()
$jobs = $this->repository->recentJobsWithManyAttempts($lowerLimit, $upperLimit);
$jobsFounds = 0;
foreach ($jobs as $job) {
- $this->assertRegExp(
+ $this->assertMatchesRegularExpression(
'/many_attempts_and_archived|many_attempts_and_scheduled/',
reset($job->export()['workable']['parameters'])
);
@@ -384,7 +384,7 @@ public function testGetSlowRecentJobs()
$jobs = $this->repository->slowRecentJobs($lowerLimit, $upperLimit);
$jobsFounds = 0;
foreach ($jobs as $job) {
- $this->assertRegExp(
+ $this->assertMatchesRegularExpression(
'/slow_job_recent_archived|slow_job_recent_scheduled/',
reset($job->export()['workable']['parameters'])
);
diff --git a/spec/Recruiter/JobSendEventsToWorkableTest.php b/spec/Recruiter/JobSendEventsToWorkableTest.php
index cf72836f..ff778b6d 100644
--- a/spec/Recruiter/JobSendEventsToWorkableTest.php
+++ b/spec/Recruiter/JobSendEventsToWorkableTest.php
@@ -2,6 +2,7 @@
namespace Recruiter;
+use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
use Recruiter\Job\Event;
@@ -24,9 +25,12 @@ protected function setUp(): void
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
}
+ /**
+ * @throws Exception
+ */
public function testTakeRetryPolicyFromRetriableInstance()
{
- $listener = $this->createPartialMock('StdClass', ['onEvent']);
+ $listener = $this->createPartialMock(EventListener::class, ['onEvent']);
$listener
->expects($this->exactly(3))
->method('onEvent')
@@ -46,14 +50,13 @@ class WorkableThatIsAlsoAnEventListener implements Workable, EventListener
{
use WorkableBehaviour;
- public function __construct($listener)
+ public function __construct(private readonly EventListener $listener)
{
- $this->listener = $listener;
}
- public function onEvent($channel, Event $e)
+ public function onEvent($channel, Event $ev)
{
- return $this->listener->onEvent($channel, $e);
+ return $this->listener->onEvent($channel, $ev);
}
public function execute()
diff --git a/spec/Recruiter/JobTest.php b/spec/Recruiter/JobTest.php
index 88334c7f..c56a31dc 100644
--- a/spec/Recruiter/JobTest.php
+++ b/spec/Recruiter/JobTest.php
@@ -53,7 +53,7 @@ public function testRetryStatisticsOnSubsequentExecutions()
$this->assertArrayHasKey('message', $lastExecution);
$this->assertArrayHasKey('trace', $lastExecution);
$this->assertEquals("Sorry, I'm good for nothing", $lastExecution['message']);
- $this->assertRegexp("/.*AlwaysFail->execute.*/", $lastExecution['trace']);
+ $this->assertMatchesRegularExpression("/.*AlwaysFail->execute.*/", $lastExecution['trace']);
}
public function testArrayAsGroupIsNotAllowed()
diff --git a/spec/Recruiter/TaggableWorkableTest.php b/spec/Recruiter/TaggableWorkableTest.php
index 949d52a3..ee85fea5 100644
--- a/spec/Recruiter/TaggableWorkableTest.php
+++ b/spec/Recruiter/TaggableWorkableTest.php
@@ -109,12 +109,12 @@ public function taggedAs()
return $this->tags;
}
- public function export()
+ public function export(): array
{
return ['tags' => $this->tags];
}
- public static function import(array $parameters)
+ public static function import(array $parameters): static
{
return new self($parameters['tags']);
}
diff --git a/src/Recruiter/Cleaner.php b/src/Recruiter/Cleaner.php
index 0c901282..b207b7eb 100644
--- a/src/Recruiter/Cleaner.php
+++ b/src/Recruiter/Cleaner.php
@@ -25,7 +25,7 @@ public function cleanArchived(Interval $gracePeriod)
return $this->repository->cleanArchived($upperLimit);
}
- public function cleanScheduled(Interval $gracePeriod = null)
+ public function cleanScheduled(?Interval $gracePeriod = null)
{
$upperLimit = T\now();
if (!is_null($gracePeriod)) {
diff --git a/src/Recruiter/Command/RecruiterJobCommand.php b/src/Recruiter/Command/RecruiterJobCommand.php
index d5f12374..77be4590 100644
--- a/src/Recruiter/Command/RecruiterJobCommand.php
+++ b/src/Recruiter/Command/RecruiterJobCommand.php
@@ -1,25 +1,21 @@
recruiter = $recruiter;
}
- protected function configure()
+ protected function configure(): void
{
$this
->setName('recruiter:command')
@@ -32,11 +28,13 @@ protected function configure()
;
}
- protected function execute(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
ShellCommand::fromCommandLine($input->getArgument('shell_command'))
->asJobOf($this->recruiter)
->inBackground()
->execute();
+
+ return self::SUCCESS;
}
}
diff --git a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
index 580b577a..49c4273c 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
@@ -22,27 +22,11 @@ class AnalyticsCommand extends Command
/**
* @var Recruiter
*/
- private $recruiter;
+ private Recruiter $recruiter;
- /**
- * @var Factory
- */
- private $factory;
-
- /**
- * @var LoggerInterface
- */
- private $logger;
-
- /**
- * @param Factory $factory
- * @param LoggerInterface $logger
- */
- public function __construct(Factory $factory, LoggerInterface $logger)
+ public function __construct(private readonly Factory $factory, private readonly LoggerInterface $logger)
{
parent::__construct();
- $this->factory = $factory;
- $this->logger = $logger;
}
protected function configure()
@@ -66,7 +50,7 @@ protected function configure()
;
}
- protected function execute(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
/** @var string */
$target = $input->getOption('target');
@@ -96,6 +80,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
$table->render();
echo PHP_EOL;
}
+
+ return self::SUCCESS;
}
private function calculateColumnsWidth(array $analytics): int
diff --git a/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php b/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
index c484c085..6ec828e7 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
@@ -23,35 +23,16 @@
class JobRecoverCommand extends Command
{
- /**
- * @var Recruiter
- */
- private $recruiter;
-
- /**
- * @var Factory
- */
- private $factory;
-
- /**
- * @var LoggerInterface
- */
- private $logger;
-
- /**
- * @var JobRepository
- */
- private $jobRepository;
+ private Recruiter $recruiter;
+ private JobRepository $jobRepository;
/**
* @param Factory $factory
* @param LoggerInterface $logger
*/
- public function __construct(Factory $factory, LoggerInterface $logger)
+ public function __construct(private readonly Factory $factory, private readonly LoggerInterface $logger)
{
parent::__construct();
- $this->factory = $factory;
- $this->logger = $logger;
}
protected function configure()
@@ -80,7 +61,7 @@ protected function configure()
;
}
- protected function execute(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
/** @var string */
$target = $input->getOption('target');
@@ -109,6 +90,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
->save();
$output->writeln("Job recovered, new job id is `{$job->id()}`");
+
+ return self::SUCCESS;
}
private function createJobFromAnArchivedJob(Job $archivedJob, JobRepository $repository): Job
diff --git a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
index f7798df2..70add3e9 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
@@ -72,12 +72,12 @@ protected function initialize(InputInterface $input, OutputInterface $output)
$this->schedulerRepository = new SchedulerRepository($db);
}
- protected function execute(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$outputData = $this->buildOutputData();
if (!$outputData) {
$output->writeln('There are no schedulers yet.');
- return null;
+ return self::SUCCESS;
}
$this->printTable($outputData, $output);
@@ -89,6 +89,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->schedulerRepository->deleteByUrn($selectedUrn);
$this->logger->info("[Recruiter] the scheduler with urn `$selectedUrn` was deleted!");
}
+
+ return self::SUCCESS;
}
private function selectUrnToDelete(array $urns, InputInterface $input, OutputInterface $output)
diff --git a/src/Recruiter/Job/Repository.php b/src/Recruiter/Job/Repository.php
index 9ea4e305..169bda40 100644
--- a/src/Recruiter/Job/Repository.php
+++ b/src/Recruiter/Job/Repository.php
@@ -131,8 +131,8 @@ public function cleanScheduled(T\Moment $upperLimit)
public function queued(
$group = null,
- T\Moment $at = null,
- T\Moment $from = null,
+ ?T\Moment $at = null,
+ ?T\Moment $from = null,
array $query = []
) {
if ($at === null) {
@@ -152,7 +152,7 @@ public function queued(
return $this->scheduled->count($query);
}
- public function postponed($group = null, T\Moment $at = null, array $query = [])
+ public function postponed($group = null, ?T\Moment $at = null, array $query = [])
{
if ($at === null) {
$at = T\now();
@@ -199,7 +199,7 @@ public function queuedGroupedBy($field, array $query = [], $group = null)
return $distinctAndCount;
}
- public function recentHistory($group = null, T\Moment $at = null, array $query = [])
+ public function recentHistory($group = null, ?T\Moment $at = null, array $query = [])
{
if ($at === null) {
$at = T\now();
diff --git a/src/Recruiter/Recruiter.php b/src/Recruiter/Recruiter.php
index 12adc429..f9dea2e8 100644
--- a/src/Recruiter/Recruiter.php
+++ b/src/Recruiter/Recruiter.php
@@ -65,12 +65,12 @@ public function queuedGroupedBy($field, array $query = [], $group = null)
/**
* @deprecated use the method `analytics` instead.
*/
- public function statistics($group = null, Moment $at = null, array $query = [])
+ public function statistics($group = null, ?Moment $at = null, array $query = [])
{
return $this->analytics($group, $at, $query);
}
- public function analytics($group = null, Moment $at = null, array $query = [])
+ public function analytics($group = null, ?Moment $at = null, array $query = [])
{
$totalsScheduledJobs = $this->jobs->scheduledCount($group, $query);
$queued = $this->jobs->queued($group, $at, $at ? $at->before(T\hour(24)) : null, $query);
From 1dad2bd1fe6ef554305fc16362e6e86746ca41a7 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:26:08 +0200
Subject: [PATCH 13/59] Fix more type errors
---
spec/Recruiter/Acceptance/HooksTest.php | 2 +-
.../WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php | 2 +-
src/Recruiter/Workable/FactoryMethodCommand.php | 7 ++++---
src/Recruiter/Workable/ShellCommand.php | 4 ++--
4 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/spec/Recruiter/Acceptance/HooksTest.php b/spec/Recruiter/Acceptance/HooksTest.php
index 68fed4bd..69db7974 100644
--- a/spec/Recruiter/Acceptance/HooksTest.php
+++ b/spec/Recruiter/Acceptance/HooksTest.php
@@ -5,7 +5,7 @@
use Recruiter\Workable\AlwaysFail;
use Recruiter\Workable\AlwaysSucceed;
use Recruiter\RetryPolicy\RetryManyTimes;
-use Symfony\Component\EventDispatcher\Event;
+use Recruiter\Job\Event;
class HooksTest extends BaseAcceptanceTestCase
{
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
index 5ceab2d7..a48487bb 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
@@ -2,7 +2,7 @@
namespace Recruiter\Acceptance;
-Recruiter\Concurrency\Timeout;
+use Recruiter\Concurrency\Timeout;
use Recruiter\Workable\ConsumingMemoryCommand;
use Timeless as T;
diff --git a/src/Recruiter/Workable/FactoryMethodCommand.php b/src/Recruiter/Workable/FactoryMethodCommand.php
index 6f7c33a0..8a354534 100644
--- a/src/Recruiter/Workable/FactoryMethodCommand.php
+++ b/src/Recruiter/Workable/FactoryMethodCommand.php
@@ -3,6 +3,7 @@
use Recruiter\Workable;
use Recruiter\Recruiter;
+use Recruiter\JobToSchedule;
class FactoryMethodCommand implements Workable
{
@@ -42,7 +43,7 @@ private function __construct(array $steps = [])
$this->steps = $steps;
}
- public function asJobOf(Recruiter $recruiter)
+ public function asJobOf(Recruiter $recruiter): JobToSchedule
{
return $recruiter->jobOf($this);
}
@@ -97,14 +98,14 @@ public function __call($method, $arguments)
return $this;
}
- public function export()
+ public function export(): array
{
return [
'steps' => $this->steps,
];
}
- public static function import(array $parameters)
+ public static function import(array $parameters): static
{
return new self($parameters['steps']);
}
diff --git a/src/Recruiter/Workable/ShellCommand.php b/src/Recruiter/Workable/ShellCommand.php
index c3531b54..ee8c3543 100644
--- a/src/Recruiter/Workable/ShellCommand.php
+++ b/src/Recruiter/Workable/ShellCommand.php
@@ -32,12 +32,12 @@ public function execute()
return $output;
}
- public function export()
+ public function export(): array
{
return ['command' => $this->commandLine];
}
- public static function import(array $parameters)
+ public static function import(array $parameters): static
{
return new self($parameters['command']);
}
From 2608689a9593f4ad216ce767c4ae0578209be4f3 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:30:20 +0200
Subject: [PATCH 14/59] Normalize + extensions
---
composer.json | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/composer.json b/composer.json
index 8d1ece1f..29e2ca4b 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,9 @@
"homepage": "https://github.com/recruiterphp/recruiter",
"require": {
"php": "^8.4",
+ "ext-bcmath": "*",
"ext-mongodb": ">=1.1",
+ "ext-posix": "*",
"dragonmantank/cron-expression": "^3.4",
"gabrielelana/byte-units": "^0.5",
"mongodb/mongodb": "^2.1",
@@ -37,17 +39,16 @@
"recruiterphp/geezer": "^6.0",
"symfony/console": "^7.3",
"symfony/event-dispatcher": "^7.3",
- "ulrichsg/getopt-php": "^4.0",
- "ext-bcmath": "*"
+ "ulrichsg/getopt-php": "^4.0"
},
"require-dev": {
+ "ext-pcntl": "*",
"dms/phpunit-arraysubset-asserts": "^0.5",
"ergebnis/composer-normalize": "^2.47",
"giorgiosironi/eris": "^1.0",
"phpstan/phpstan": "*",
"phpunit/phpunit": "^10.0",
- "rector/rector": "^2.1",
- "ext-pcntl": "*"
+ "rector/rector": "^2.1"
},
"suggest": {
"symfony/console": "In order to use Recruiter\\Command\\RecruiterJobCommand."
From 1a0348e7c1c2e26ab6d980cc48e9167611b0b1ec Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:31:00 +0200
Subject: [PATCH 15/59] Scan directory for Eris
---
phpstan.neon | 2 ++
1 file changed, 2 insertions(+)
diff --git a/phpstan.neon b/phpstan.neon
index dc25ee1c..dc4e3b09 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -3,6 +3,8 @@ parameters:
paths:
- src
- spec
+ scanDirectories:
+ - %currentWorkingDirectory%/vendor/giorgiosironi/eris/src/
ignoreErrors:
- '#Instantiated class Recruiter\\Workable\\ThisClassDoesnNotExists not found.#'
- '#Constructor of class Recruiter\\Workable\\FailsInConstructor has an unused parameter \$parameters.#'
From 791f2fb6397a030115e922ca052a23c7d1c6367c Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:34:17 +0200
Subject: [PATCH 16/59] Fix configuration of phpstan
---
phpstan.neon | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/phpstan.neon b/phpstan.neon
index dc4e3b09..7f86cc94 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -7,11 +7,7 @@ parameters:
- %currentWorkingDirectory%/vendor/giorgiosironi/eris/src/
ignoreErrors:
- '#Instantiated class Recruiter\\Workable\\ThisClassDoesnNotExists not found.#'
- - '#Constructor of class Recruiter\\Workable\\FailsInConstructor has an unused parameter \$parameters.#'
- - '#Static call to instance method stdClass::import\(\)#'
- - '#Call to function is_callable\(\) with .recruiter_stept_back. will always evaluate to false.#'
- - '#Call to function is_callable\(\) with .recruiter_becameā¦. will always evaluate to false.#'
- '#Function recruiter_became_master not found.#'
- '#Function recruiter_stept_back not found.#'
- - '#Call to an undefined method Traversable::toArray\(\).#'
+ - '#Unsafe usage of new static\(\).#'
inferPrivatePropertyTypeFromConstructor: true
From 7787a5d412673b49664b051d5dcd9759fff8e69c Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:38:24 +0200
Subject: [PATCH 17/59] Increase PHPStan level to 1
---
phpstan.neon | 4 +++-
spec/Recruiter/RetryPolicy/TimeTableTest.php | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/phpstan.neon b/phpstan.neon
index 7f86cc94..e80c96d0 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,5 +1,5 @@
parameters:
- level: 0
+ level: 1
paths:
- src
- spec
@@ -10,4 +10,6 @@ parameters:
- '#Function recruiter_became_master not found.#'
- '#Function recruiter_stept_back not found.#'
- '#Unsafe usage of new static\(\).#'
+ - '#Call to an undefined static method Sink\\BlackHole::whateverStaticMethod\(\).#'
+ - '#Constructor of class Recruiter\\Workable\\FailsInConstructor has an unused parameter \$parameters.#'
inferPrivatePropertyTypeFromConstructor: true
diff --git a/spec/Recruiter/RetryPolicy/TimeTableTest.php b/spec/Recruiter/RetryPolicy/TimeTableTest.php
index 2e46f143..dd93d037 100644
--- a/spec/Recruiter/RetryPolicy/TimeTableTest.php
+++ b/spec/Recruiter/RetryPolicy/TimeTableTest.php
@@ -119,7 +119,7 @@ private function givenJobThat(T\Moment $wasCreatedAt)
private function jobThatWasCreated($relativeTime)
{
- $wasCreatedAt = T\Moment::fromTimestamp(strtotime($relativeTime), T\now()->seconds());
+ $wasCreatedAt = T\Moment::fromTimestamp(strtotime($relativeTime));
$job = $this->getMockBuilder('Recruiter\JobAfterFailure')
->disableOriginalConstructor()
->setMethods(['createdAt', 'scheduleAt'])
From 66456e366d98efc94dbcef9b97dd246f59f165a8 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:52:06 +0200
Subject: [PATCH 18/59] Separate long tests
---
Makefile | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 3df22988..df96bd4d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: build up down test phpstan rector fix-cs install update shell logs clean
+.PHONY: build up down test test-long phpstan rector fix-cs install update shell logs clean
# Build the Docker image
build:
@@ -22,7 +22,11 @@ update:
# Run all tests except the long ones
test: up
- docker compose exec php vendor/bin/phpunit
+ docker compose exec php vendor/bin/phpunit --exclude-group=long
+
+# Run long tests specifically
+test-long: up
+ docker compose exec php vendor/bin/phpunit --group=long
phpstan: up
docker compose exec php vendor/bin/phpstan --memory-limit=2G
From a22871a07f34b160afe303161d618e37cae84e4f Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 03:53:50 +0200
Subject: [PATCH 19/59] Fix constructor
---
src/Recruiter/Workable/FailsInConstructor.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Recruiter/Workable/FailsInConstructor.php b/src/Recruiter/Workable/FailsInConstructor.php
index 0c1e25df..9523f5b0 100644
--- a/src/Recruiter/Workable/FailsInConstructor.php
+++ b/src/Recruiter/Workable/FailsInConstructor.php
@@ -9,7 +9,7 @@ class FailsInConstructor implements Workable
{
use WorkableBehaviour;
- public function __construct($parameters = [], $fromRecruiter = true)
+ public function __construct(protected array $parameters = [], $fromRecruiter = true)
{
if ($fromRecruiter) {
throw new Exception("I am supposed to fail in constructor code for testing purpose");
From d5e83bc4ad986b7426604ca45800c47fc0c81e62 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 11:54:26 +0200
Subject: [PATCH 20/59] Get MONGODB_URI from environment
---
src/Recruiter/Infrastructure/Command/CleanerCommand.php | 3 ++-
src/Recruiter/Infrastructure/Command/RecruiterCommand.php | 3 ++-
src/Recruiter/Infrastructure/Command/WorkerCommand.php | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/Recruiter/Infrastructure/Command/CleanerCommand.php b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
index 6a83f108..302d5b71 100644
--- a/src/Recruiter/Infrastructure/Command/CleanerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
@@ -127,8 +127,9 @@ public function description(): string
public function definition(): InputDefinition
{
+ $defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
return new InputDefinition([
- new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', 'mongodb://localhost:27017/recruiter'),
+ new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('clean-after', 'c', InputOption::VALUE_REQUIRED, 'delete jobs after :period', '5days'),
new InputOption('wait-at-least', null, InputOption::VALUE_REQUIRED, 'Time to wait at least before to search for jobs to clear', '1m'),
new InputOption('wait-at-most', null, InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling', '3m'),
diff --git a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
index 8d06743c..61f97b95 100644
--- a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
+++ b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
@@ -183,8 +183,9 @@ public function description(): string
public function definition(): InputDefinition
{
+ $defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
return new InputDefinition([
- new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', 'mongodb://localhost:27017/recruiter'),
+ new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling (milliseconds)', '1600ms'),
new InputOption('backoff-from', 'f', InputOption::VALUE_REQUIRED, 'Time to wait at least before to search for new jobs (milliseconds)', '200ms'),
new InputOption('lease-time', 'l', InputOption::VALUE_REQUIRED, 'Maximum time to hold a lock before a refresh', '60s'),
diff --git a/src/Recruiter/Infrastructure/Command/WorkerCommand.php b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
index 45de89ad..626091e0 100644
--- a/src/Recruiter/Infrastructure/Command/WorkerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
@@ -119,8 +119,9 @@ public function description(): string
public function definition(): InputDefinition
{
+ $defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
return new InputDefinition([
- new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', 'mongodb://localhost:27017/recruiter'),
+ new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling', '6400ms'),
new InputOption('backoff-from', null, InputOption::VALUE_REQUIRED, 'Time to wait at least before to search for new jobs', '200ms'),
new InputOption('memory-limit', 'm', InputOption::VALUE_REQUIRED, 'Maximum amount of memory allocable', '64MB'),
From 64de1b0ce0021b581cd816cebc2b54af21cda86b Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 12:18:28 +0200
Subject: [PATCH 21/59] Fix mock call with spy
---
...rkableImplementsFinalizerInterfaceTest.php | 55 ++++++++++++-------
1 file changed, 35 insertions(+), 20 deletions(-)
diff --git a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
index 40c86b12..7998d92d 100644
--- a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
+++ b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
@@ -12,6 +12,7 @@ class FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest exte
{
private MockObject&Repository $repository;
private EventDispatcherInterface $dispatcher;
+ private ListenerSpy $listener;
/**
* @throws \PHPUnit\Framework\MockObject\Exception
@@ -24,44 +25,57 @@ protected function setUp(): void
->getMock();
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
+ $this->listener = new ListenerSpy();
}
- public function testFinalizableFailureMethodsAreCalledWhenJobFails()
+ public function testFinalizableFailureMethodsAreCalledWhenJobFails(): void
{
$exception = new \Exception('job was failed');
- $listener = $this->createPartialMock('StdClass', ['methodWasCalled']);
- $listener
- ->expects($this->exactly(3))
- ->method('methodWasCalled')
- ->withConsecutive(
- [$this->equalTo('afterFailure'), $exception],
- [$this->equalTo('afterLastFailure'), $exception],
- [$this->equalTo('finalize'), $exception]
- );
+
$workable = new FinalizableWorkable(function () use ($exception): void {
throw $exception;
- }, $listener);
+ }, $this->listener);
$job = Job::around($workable, $this->repository);
$job->execute($this->dispatcher);
+
+ $calls = $this->listener->calls;
+ $this->assertCount(3, $calls);
+
+ $this->assertSame('afterFailure', $calls[0][0]);
+ $this->assertSame($exception, $calls[0][1]);
+
+ $this->assertSame('afterLastFailure', $calls[1][0]);
+ $this->assertSame($exception, $calls[1][1]);
+
+ $this->assertSame('finalize', $calls[2][0]);
+ $this->assertSame($exception, $calls[2][1]);
}
+
public function testFinalizableSuccessfullMethodsAreCalledWhenJobIsDone()
{
- $listener = $this->createPartialMock('StdClass', ['methodWasCalled']);
- $listener
- ->expects($this->exactly(2))
- ->method('methodWasCalled')
- ->withConsecutive(
- [$this->equalTo('afterSuccess')],
- [$this->equalTo('finalize')]
- );
$workable = new FinalizableWorkable(function () {
return true;
- }, $listener);
+ }, $this->listener);
$job = Job::around($workable, $this->repository);
$job->execute($this->dispatcher);
+
+ $calls = $this->listener->calls;
+ $this->assertCount(2, $calls);
+ $this->assertSame('afterSuccess', $calls[0][0]);
+ $this->assertSame('finalize', $calls[1][0]);
+ }
+}
+
+class ListenerSpy
+{
+ public array $calls = [];
+
+ public function methodWasCalled(string $name, ?\Throwable $exception = null): void
+ {
+ $this->calls[] = [$name, $exception];
}
}
@@ -76,6 +90,7 @@ class FinalizableWorkable implements Workable, Finalizable
public function __construct(callable $whatToDo, $listener)
{
+ $this->parameters = [];
$this->listener = $listener;
$this->whatToDo = $whatToDo;
}
From f452a397709e3c714248c26b58fb5c600d624d38 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 12:22:29 +0200
Subject: [PATCH 22/59] Add PHP-CS-Fixer
---
.gitignore | 3 +--
.php-cs-fixer.dist.php | 25 +++++++++++++++++++++++++
composer.json | 1 +
3 files changed, 27 insertions(+), 2 deletions(-)
create mode 100644 .php-cs-fixer.dist.php
diff --git a/.gitignore b/.gitignore
index 62560d1e..d1b4fe30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
-.*
-!.github
+.*.cache
composer.phar
composer.lock
vendor/
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
new file mode 100644
index 00000000..389eada7
--- /dev/null
+++ b/.php-cs-fixer.dist.php
@@ -0,0 +1,25 @@
+setRiskyAllowed(true)
+ ->setRules([
+ '@PSR12' => true,
+ '@Symfony' => true,
+ 'array_indentation' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'concat_space' => ['spacing' => 'one'],
+ 'declare_strict_types' => true,
+ 'string_implicit_backslashes' => true,
+ 'list_syntax' => ['syntax' => 'short'],
+ 'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
+ 'ordered_imports' => true,
+ 'phpdoc_to_comment' => false,
+ 'trailing_comma_in_multiline' => ['elements' => ['arrays', 'arguments', 'parameters']],
+ 'visibility_required' => ['elements' => ['property', 'method', 'const']],
+ ])
+ ->setFinder(
+ PhpCsFixer\Finder::create()
+ ->in(__DIR__ . '/src')
+ ->in(__DIR__ . '/spec')
+ )
+;
diff --git a/composer.json b/composer.json
index 29e2ca4b..1fd7cb23 100644
--- a/composer.json
+++ b/composer.json
@@ -45,6 +45,7 @@
"ext-pcntl": "*",
"dms/phpunit-arraysubset-asserts": "^0.5",
"ergebnis/composer-normalize": "^2.47",
+ "friendsofphp/php-cs-fixer": "^3.85",
"giorgiosironi/eris": "^1.0",
"phpstan/phpstan": "*",
"phpunit/phpunit": "^10.0",
From 26e2aeca1292b5a7e79cc1e159a38481b3b480a2 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 12:23:06 +0200
Subject: [PATCH 23/59] Disable strict types for now
---
.php-cs-fixer.dist.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 389eada7..d1055d88 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -8,7 +8,7 @@
'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'concat_space' => ['spacing' => 'one'],
- 'declare_strict_types' => true,
+ /* 'declare_strict_types' => true, */
'string_implicit_backslashes' => true,
'list_syntax' => ['syntax' => 'short'],
'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
From 0ba72786d1df4c56761db94e145df27ebc572c9a Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 12:23:20 +0200
Subject: [PATCH 24/59] Fix Coding Standards
---
spec/Recruiter/Acceptance/AssignmentTest.php | 6 +-
.../Acceptance/BaseAcceptanceTestCase.php | 68 ++++---
spec/Recruiter/Acceptance/EnduranceTest.php | 47 ++---
.../Acceptance/FaultToleranceTest.php | 30 +--
spec/Recruiter/Acceptance/HooksTest.php | 45 +++--
.../RepeatableJobsAreScheduledTest.php | 17 +-
.../Acceptance/SyncronousExecutionTest.php | 7 +-
...rGuaranteedToExitWhenAMemoryLeakOccurs.php | 14 +-
...itWithFailureCodeInCaseOfExceptionTest.php | 3 +-
...WorkerGuaranteedToRetireAfterDeathTest.php | 2 +-
.../Acceptance/WorkerRepositoryTest.php | 4 +-
spec/Recruiter/CleanerTest.php | 13 +-
spec/Recruiter/FactoryTest.php | 6 +-
...rkableImplementsFinalizerInterfaceTest.php | 14 +-
.../Infrastructure/Memory/MemoryLimitTest.php | 1 +
spec/Recruiter/Job/EventTest.php | 5 +-
spec/Recruiter/Job/RepositoryTest.php | 180 +++++++++---------
.../JobCallCustomMethodOnWorkableTest.php | 11 +-
.../Recruiter/JobSendEventsToWorkableTest.php | 10 +-
...keRetryPolicyFromRetriableWorkableTest.php | 7 +-
spec/Recruiter/JobTest.php | 19 +-
.../JobToBePassedRetryStatisticsTest.php | 5 +-
spec/Recruiter/JobToScheduleTest.php | 68 ++++---
spec/Recruiter/PickAvailableWorkersTest.php | 26 +--
.../RetryPolicy/ExponentialBackoffTest.php | 16 +-
.../RetriableExceptionFilterTest.php | 50 ++---
.../RetryPolicy/SelectByExceptionTest.php | 35 ++--
spec/Recruiter/RetryPolicy/TimeTableTest.php | 35 ++--
spec/Recruiter/SchedulePolicy/CronTest.php | 7 +-
spec/Recruiter/TaggableWorkableTest.php | 7 +-
spec/Recruiter/WaitStrategyTest.php | 14 +-
.../Workable/FactoryMethodCommandTest.php | 12 +-
spec/Recruiter/Workable/ShellCommandTest.php | 3 +-
spec/Recruiter/WorkablePersistenceTest.php | 2 +-
spec/Recruiter/WorkerProcessTest.php | 18 +-
spec/Sink/BlackHoleTest.php | 2 +-
spec/Timeless/IntervalParseTest.php | 7 +-
spec/Timeless/MongoDateTest.php | 8 +-
src/Recruiter/AlreadyRunningException.php | 4 +-
.../CannotRetireWorkerAtWorkException.php | 5 +-
src/Recruiter/Cleaner.php | 2 +-
src/Recruiter/Command/RecruiterJobCommand.php | 6 +-
src/Recruiter/Factory.php | 13 +-
src/Recruiter/Finalizable.php | 9 +-
src/Recruiter/FinalizableBehaviour.php | 9 +-
.../Command/Bko/AnalyticsCommand.php | 12 +-
.../Command/Bko/JobRecoverCommand.php | 19 +-
.../Command/Bko/RemoveSchedulerCommand.php | 21 +-
.../Infrastructure/Command/CleanerCommand.php | 26 ++-
.../Command/RecruiterCommand.php | 35 ++--
.../Infrastructure/Command/WorkerCommand.php | 20 +-
.../Filesystem/BootstrapFile.php | 18 +-
.../Infrastructure/Memory/MemoryLimit.php | 14 +-
.../Memory/MemoryLimitExceededException.php | 2 +-
.../Persistence/Mongodb/URI.php | 7 +-
src/Recruiter/Job.php | 72 +++----
src/Recruiter/Job/Event.php | 2 +
src/Recruiter/Job/Repository.php | 152 +++++++--------
src/Recruiter/JobAfterFailure.php | 5 +-
src/Recruiter/JobExecution.php | 10 +-
src/Recruiter/JobToSchedule.php | 16 +-
src/Recruiter/Recruiter.php | 59 +++---
src/Recruiter/Repeatable.php | 6 +-
src/Recruiter/RepeatableInJob.php | 18 +-
src/Recruiter/Retriable.php | 4 +-
src/Recruiter/RetryPolicy.php | 13 +-
src/Recruiter/RetryPolicy/DoNotDoItAgain.php | 2 +-
.../RetryPolicy/ExponentialBackoff.php | 13 +-
.../RetryPolicy/RetriableException.php | 9 +-
.../RetryPolicy/RetriableExceptionFilter.php | 24 +--
src/Recruiter/RetryPolicy/RetryForever.php | 11 +-
src/Recruiter/RetryPolicy/RetryManyTimes.php | 11 +-
.../RetryPolicy/SelectByException.php | 49 ++---
.../RetryPolicy/SelectByExceptionBuilder.php | 8 +-
src/Recruiter/RetryPolicy/TimeTable.php | 26 +--
src/Recruiter/RetryPolicyBehaviour.php | 4 +-
src/Recruiter/RetryPolicyInJob.php | 14 +-
src/Recruiter/SchedulePolicy.php | 12 +-
src/Recruiter/SchedulePolicy/Cron.php | 11 +-
src/Recruiter/SchedulePolicy/EveryMinutes.php | 2 -
src/Recruiter/SchedulePolicyInJob.php | 14 +-
src/Recruiter/Scheduler.php | 31 ++-
src/Recruiter/Scheduler/Repository.php | 13 +-
src/Recruiter/SynchronousExecutionReport.php | 6 +-
src/Recruiter/Taggable.php | 2 +-
src/Recruiter/WaitStrategy.php | 8 +-
src/Recruiter/Workable.php | 8 +-
src/Recruiter/Workable/AlwaysFail.php | 4 +-
.../Workable/ConsumingMemoryCommand.php | 3 +-
.../Workable/FactoryMethodCommand.php | 17 +-
src/Recruiter/Workable/FailsInConstructor.php | 4 +-
src/Recruiter/Workable/LazyBones.php | 5 +-
.../RecoverRepeatableFromException.php | 11 +-
.../Workable/RecoverWorkableFromException.php | 9 +-
.../Workable/SampleRepeatableCommand.php | 7 +-
src/Recruiter/Workable/ShellCommand.php | 6 +-
src/Recruiter/Workable/ThrowsFatalError.php | 1 +
src/Recruiter/WorkableBehaviour.php | 6 +-
src/Recruiter/WorkableInJob.php | 18 +-
src/Recruiter/Worker.php | 39 ++--
src/Recruiter/Worker/Process.php | 2 +-
src/Recruiter/Worker/Repository.php | 11 +-
.../WorkerDiedInTheLineOfDutyException.php | 5 +-
src/Recruiter/functions.php | 5 +-
src/Sink/BlackHole.php | 4 +-
src/Timeless/ClockInterface.php | 2 +-
src/Timeless/Interval.php | 30 +--
src/Timeless/InvalidIntervalFormat.php | 4 +-
src/Timeless/Moment.php | 11 +-
src/Timeless/MongoDate.php | 3 +-
src/Timeless/functions.php | 1 +
111 files changed, 938 insertions(+), 951 deletions(-)
diff --git a/spec/Recruiter/Acceptance/AssignmentTest.php b/spec/Recruiter/Acceptance/AssignmentTest.php
index 74d9edf7..4c764bb7 100644
--- a/spec/Recruiter/Acceptance/AssignmentTest.php
+++ b/spec/Recruiter/Acceptance/AssignmentTest.php
@@ -1,4 +1,5 @@
asJobOf($this->recruiter)
->inBackground()
- ->execute();
+ ->execute()
+ ;
$worker = $this->recruiter->hire($memoryLimit);
- list ($assignments, $totalNumber) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $totalNumber] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(1, count($assignments));
$this->assertEquals(1, $totalNumber);
$this->assertTrue((bool) $worker->work());
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index 15d1ff4a..f88d26a1 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -1,11 +1,11 @@
until(function () use ($expectedNumber) {
- $this->recruiter->retireDeadWorkers(new DateTimeImmutable(), T\seconds(0));
+ $this->recruiter->retireDeadWorkers(new \DateTimeImmutable(), T\seconds(0));
+
return $this->numberOfWorkers() == $expectedNumber;
- });
+ })
+ ;
}
protected function startRecruiter(): array
@@ -101,13 +103,16 @@ protected function startRecruiter(): array
$process = proc_open('exec php bin/recruiter start:recruiter --backoff-to 5000ms --lease-time 10s --considered-dead-after 20s >> /tmp/recruiter.log 2>&1', $descriptors, $pipes, $cwd);
- Timeout::inSeconds(1, "recruiter to be up")
+ Timeout::inSeconds(1, 'recruiter to be up')
->until(function () use ($process) {
$status = proc_get_status($process);
+
return $status['running'];
- });
+ })
+ ;
$this->processRecruiter = [$process, $pipes, 'recruiter'];
+
return $this->processRecruiter;
}
@@ -120,11 +125,13 @@ protected function startCleaner(): array
];
$cwd = __DIR__ . '/../../../';
$process = proc_open('exec php bin/recruiter start:cleaner --wait-at-least=5s --wait-at-most=1m --lease-time 20s >> /tmp/cleaner.log 2>&1', $descriptors, $pipes, $cwd);
- Timeout::inSeconds(1, "cleaner to be up")
+ Timeout::inSeconds(1, 'cleaner to be up')
->until(function () use ($process) {
$status = proc_get_status($process);
+
return $status['running'];
- });
+ })
+ ;
$this->processCleaner = [$process, $pipes, 'cleaner'];
return $this->processCleaner;
@@ -147,62 +154,68 @@ protected function startWorker(array $additionalOptions = [])
$cwd = __DIR__ . '/../../../';
$process = proc_open("exec php bin/recruiter start:worker $options >> /tmp/worker.log 2>&1", $descriptors, $pipes, $cwd);
- Timeout::inSeconds(1, "worker to be up")
+ Timeout::inSeconds(1, 'worker to be up')
->until(function () use ($process) {
$status = proc_get_status($process);
+
return $status['running'];
- });
+ })
+ ;
// proc_get_status($process);
$this->processWorkers[] = [$process, $pipes, 'worker'];
+
return end($this->processWorkers);
}
protected function stopProcessWithSignal(array $processAndPipes, $signal): void
{
- list($process, $pipes, $name) = $processAndPipes;
+ [$process, $pipes, $name] = $processAndPipes;
proc_terminate($process, $signal);
$this->lastStatus = proc_get_status($process);
- Timeout
- ::inSeconds(30, function () use ($signal) {
- return 'termination of process: ' . var_export($this->lastStatus, true) . " after sending the `$signal` signal to it";
- })
+ Timeout::inSeconds(30, function () use ($signal) {
+ return 'termination of process: ' . var_export($this->lastStatus, true) . " after sending the `$signal` signal to it";
+ })
->until(function () use ($process) {
$this->lastStatus = proc_get_status($process);
- return $this->lastStatus['running'] == false;
- });
+
+ return false == $this->lastStatus['running'];
+ })
+ ;
}
/**
- * @param integer $duration milliseconds
+ * @param int $duration milliseconds
*/
protected function enqueueJob($duration = 10, $tag = 'generic'): void
{
- $workable = ShellCommand::fromCommandLine("sleep " . ($duration / 1000));
+ $workable = ShellCommand::fromCommandLine('sleep ' . ($duration / 1000));
$workable
->asJobOf($this->recruiter)
->inGroup($tag)
->inBackground()
- ->execute();
- $this->jobs++;
+ ->execute()
+ ;
+ ++$this->jobs;
}
protected function enqueueJobWithRetryPolicy(int $duration, RetryPolicy $retryPolicy): void
{
- $workable = ShellCommand::fromCommandLine("sleep " . ($duration / 1000));
+ $workable = ShellCommand::fromCommandLine('sleep ' . ($duration / 1000));
$workable
->asJobOf($this->recruiter)
->retryWithPolicy($retryPolicy)
->inBackground()
- ->execute();
- $this->jobs++;
+ ->execute()
+ ;
+ ++$this->jobs;
}
protected function start(int $workers): void
{
$this->startRecruiter();
$this->startCleaner();
- for ($i = 0; $i < $workers; $i++) {
+ for ($i = 0; $i < $workers; ++$i) {
$this->startWorker();
}
}
@@ -252,12 +265,13 @@ protected function files(): string
$logs = '';
if (getenv('TEST_DUMP')) {
foreach ($this->files as $file) {
- $logs .= $file. ":". PHP_EOL;
+ $logs .= $file . ':' . PHP_EOL;
$logs .= file_get_contents($file);
}
} else {
$logs .= var_export($this->files, true);
}
+
return $logs;
}
@@ -267,7 +281,7 @@ private function optionsToString(array $options = []): string
foreach ($options as $option => $value) {
$optionsString .= " --$option=$value";
- };
+ }
return $optionsString;
}
diff --git a/spec/Recruiter/Acceptance/EnduranceTest.php b/spec/Recruiter/Acceptance/EnduranceTest.php
index 66d74e72..a0406630 100644
--- a/spec/Recruiter/Acceptance/EnduranceTest.php
+++ b/spec/Recruiter/Acceptance/EnduranceTest.php
@@ -1,12 +1,12 @@
hook(Listener\log('/tmp/recruiter-test-iterations.log'))
->hook(Listener\collectFrequencies())
->disableShrinking()
->then(function ($tuple): void {
- list ($workers, $actions) = $tuple;
+ [$workers, $actions] = $tuple;
$this->clean();
$this->start($workers);
foreach ($actions as $action) {
@@ -87,7 +88,7 @@ function ($milliseconds) {
$method = array_shift($arguments);
call_user_func_array(
[$this, $method],
- $arguments
+ $arguments,
);
} else {
$this->$action();
@@ -98,12 +99,13 @@ function ($milliseconds) {
Timeout::inSeconds(
$estimatedTime,
function () {
- return "all $this->jobs jobs to be performed. Now is " . date('c') . " Logs: " . $this->files();
- }
+ return "all $this->jobs jobs to be performed. Now is " . date('c') . ' Logs: ' . $this->files();
+ },
)
->until(function () {
return $this->jobRepository->countArchived() === $this->jobs;
- });
+ })
+ ;
$at = T\now();
$statistics = $this->recruiter->statistics($tag = null, $at);
@@ -118,7 +120,8 @@ function () {
}
// TODO: add tolerance
$this->assertEquals($statistics['throughput']['value'], $cumulativeThroughput);
- });
+ })
+ ;
}
private function logAction($action)
@@ -126,11 +129,11 @@ private function logAction($action)
file_put_contents(
$this->actionLog,
sprintf(
- "[ACTIONS][PHPUNIT][%s] %s" . PHP_EOL,
+ '[ACTIONS][PHPUNIT][%s] %s' . PHP_EOL,
date('c'),
- json_encode($action)
+ json_encode($action),
),
- FILE_APPEND
+ FILE_APPEND,
);
}
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index 9e2daaa8..abe2bcfd 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -1,11 +1,11 @@
recruiter->hire($memoryLimit);
$this->recruiter->bookJobsForWorkers();
$this->recruiter->rollbackLockedJobs();
- list ($assignments, $totalNumber) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $totalNumber] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(1, count($assignments));
$this->assertEquals(1, $totalNumber);
}
@@ -28,30 +28,31 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor()
->asJobOf($this->recruiter)
->inBackground()
->retryWithPolicy(RetryManyTimes::forTimes(1, 0))
- ->execute();
+ ->execute()
+ ;
$worker = $this->startWorker();
$this->waitForNumberOfWorkersToBe(1);
- list ($assignments, $_) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(1, count($assignments));
sleep(2);
$jobDocument = current($this->scheduled->find()->toArray());
$this->assertEquals(1, $jobDocument['attempts']);
- $this->assertEquals('Recruiter\\Workable\\FailsInConstructor', $jobDocument['workable']['class']);
+ $this->assertEquals('Recruiter\Workable\FailsInConstructor', $jobDocument['workable']['class']);
$this->assertStringContainsString('This job failed while instantiating a workable', $jobDocument['last_execution']['message']);
$this->assertStringContainsString('I am supposed to fail in constructor code for testing purpose', $jobDocument['last_execution']['message']);
- list ($assignments, $_) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(1, count($assignments));
sleep(2);
$jobDocument = current($this->archived->find()->toArray());
$this->assertEquals(2, $jobDocument['attempts']);
- $this->assertEquals('Recruiter\\Workable\\FailsInConstructor', $jobDocument['workable']['class']);
+ $this->assertEquals('Recruiter\Workable\FailsInConstructor', $jobDocument['workable']['class']);
$this->assertStringContainsString('This job failed while instantiating a workable', $jobDocument['last_execution']['message']);
$this->assertStringContainsString('I am supposed to fail in constructor code for testing purpose', $jobDocument['last_execution']['message']);
- list ($assignments, $_) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(0, count($assignments));
}
@@ -66,7 +67,8 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies()
->asJobOf($this->recruiter)
->inBackground()
->retryWithPolicy(RetryManyTimes::forTimes(1, 0))
- ->execute();
+ ->execute()
+ ;
// Right now we recover for dead jobs when we
// Recruiter::retireDeadWorkers and when we
@@ -78,7 +80,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies()
// First execution of the job
$worker = $this->startWorker();
$this->waitForNumberOfWorkersToBe(1);
- list ($assignments, $_) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(1, count($assignments));
sleep(2);
// The worker is dead and the job is not properly scheduled
@@ -89,7 +91,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies()
$worker = $this->startWorker();
$this->waitForNumberOfWorkersToBe(1);
// Here the job is assigned and rescheduled by the retry policy because found crashed
- list ($assignments, $_) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(1, count($assignments));
sleep(2);
// The worker is dead and the job is not properly scheduled
@@ -103,7 +105,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies()
// Here the job is assigned and archived by the retry policy
// because found crashed and because it has been already
// executed 2 times
- list ($assignments, $_) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(1, count($assignments));
sleep(1);
// The worker is not dead and the job is not scheduled anymore
diff --git a/spec/Recruiter/Acceptance/HooksTest.php b/spec/Recruiter/Acceptance/HooksTest.php
index 69db7974..07b03d30 100644
--- a/spec/Recruiter/Acceptance/HooksTest.php
+++ b/spec/Recruiter/Acceptance/HooksTest.php
@@ -1,16 +1,18 @@
memoryLimit = new MemoryLimit('64MB');
@@ -26,13 +28,15 @@ public function testAfterFailureWithoutRetryEventIsFired()
'job.failure.last',
function (Event $event): void {
$this->events[] = $event;
- }
- );
+ },
+ )
+ ;
$job = (new AlwaysFail())
->asJobOf($this->recruiter)
->inBackground()
- ->execute();
+ ->execute()
+ ;
$worker = $this->recruiter->hire($this->memoryLimit);
$this->recruiter->assignJobsToWorkers();
@@ -52,21 +56,23 @@ public function testAfterLastFailureEventIsFired()
'job.failure.last',
function (Event $event): void {
$this->events[] = $event;
- }
- );
+ },
+ )
+ ;
$job = (new AlwaysFail())
->asJobOf($this->recruiter)
->retryWithPolicy(RetryManyTimes::forTimes(1, 0))
->inBackground()
- ->execute();
+ ->execute()
+ ;
$runAJob = function ($howManyTimes, $worker): void {
for ($i = 0; $i < $howManyTimes;) {
- list($_, $assigned) = $this->recruiter->assignJobsToWorkers();
+ [$_, $assigned] = $this->recruiter->assignJobsToWorkers();
$worker->work();
if ($assigned > 0) {
- $i++;
+ ++$i;
}
}
};
@@ -88,13 +94,15 @@ public function testJobStartedIsFired()
'job.started',
function (Event $event): void {
$this->events[] = $event;
- }
- );
+ },
+ )
+ ;
$job = (new AlwaysSucceed())
->asJobOf($this->recruiter)
->inBackground()
- ->execute();
+ ->execute()
+ ;
$worker = $this->recruiter->hire($this->memoryLimit);
$this->recruiter->assignJobsToWorkers();
@@ -113,18 +121,21 @@ public function testJobEndedIsFired()
'job.ended',
function (Event $event): void {
$this->events[] = $event;
- }
- );
+ },
+ )
+ ;
(new AlwaysSucceed())
->asJobOf($this->recruiter)
->inBackground()
- ->execute();
+ ->execute()
+ ;
(new AlwaysFail())
->asJobOf($this->recruiter)
->inBackground()
- ->execute();
+ ->execute()
+ ;
$worker = $this->recruiter->hire($this->memoryLimit);
$this->recruiter->assignJobsToWorkers();
diff --git a/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php b/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
index a9c6ab34..e847ea58 100644
--- a/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
+++ b/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
@@ -1,14 +1,13 @@
0,
'group' => 'generic',
'workable' => [
- 'class' => 'Recruiter\\Workable\\SampleRepeatableCommand',
+ 'class' => 'Recruiter\Workable\SampleRepeatableCommand',
'parameters' => [],
'method' => 'execute',
],
@@ -48,12 +47,12 @@ public function testARepeatableJobIsScheduledAtExpectedScheduledTime()
'executions' => 1,
],
'retry_policy' => [
- 'class' => 'Recruiter\\RetryPolicy\\ExponentialBackoff',
+ 'class' => 'Recruiter\RetryPolicy\ExponentialBackoff',
'parameters' => [
'retry_how_many_times' => 2,
'seconds_to_initially_wait_before_retry' => 5,
],
- ]
+ ],
], $jobData);
}
@@ -72,7 +71,7 @@ public function testOnlyASingleJobAreScheduledForTheSameSchedulingTime()
$this->assertEquals(
T\MongoDate::from(Moment::fromTimestamp($expectedScheduleDate)),
- $jobs[0]->export()['scheduled_at']
+ $jobs[0]->export()['scheduled_at'],
);
}
@@ -134,8 +133,8 @@ public function testSchedulersAreUniqueOnUrn()
private function IHaveAScheduleWithALongStory(string $urn, $attempts)
{
$scheduleTimes = [];
- for ($i = 1; $i <= $attempts; $i++) {
- $scheduleTimes[] = strtotime("2018-05-" . $i . "T15:00:00");
+ for ($i = 1; $i <= $attempts; ++$i) {
+ $scheduleTimes[] = strtotime('2018-05-' . $i . 'T15:00:00');
}
$schedulePolicy = new FixedSchedulePolicy($scheduleTimes);
@@ -171,12 +170,14 @@ private function recruiterScheduleJobsNTimes(int $nth = 1): void
private function fetchScheduledJobs()
{
$jobsRepository = new JobsRepository($this->recruiterDb);
+
return $jobsRepository->all();
}
private function fetchSchedulers()
{
$schedulersRepository = new SchedulersRepository($this->recruiterDb);
+
return $schedulersRepository->all();
}
}
diff --git a/spec/Recruiter/Acceptance/SyncronousExecutionTest.php b/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
index 6161ff16..34f3dde6 100644
--- a/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
+++ b/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
@@ -1,4 +1,5 @@
asJobOf($this->recruiter)
->inBackground()
- ->execute();
+ ->execute()
+ ;
$report = $this->recruiter->flushJobsSynchronously();
@@ -40,7 +42,8 @@ private function enqueueAnAnswerJob($answer, $scheduledAt)
->asJobOf($this->recruiter)
->scheduleAt($scheduledAt)
->inBackground()
- ->execute();
+ ->execute()
+ ;
}
}
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
index a48487bb..0ab1fb42 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
@@ -10,6 +10,7 @@ class WorkerGuaranteedToExitWhenAMemoryLeakOccurs extends BaseAcceptanceTestCase
{
/**
* @group acceptance
+ *
* @dataProvider provideMemoryConsumptions
*/
public function testWorkerKillItselfAfterAMemoryLeakButNotAfterABigMemoryConsumptionWithoutLeak($withMemoryLeak, $howManyItems, $memoryLimit, $expectedWorkerAlive)
@@ -20,7 +21,8 @@ public function testWorkerKillItselfAfterAMemoryLeakButNotAfterABigMemoryConsump
]))
->asJobOf($this->recruiter)
->inBackground()
- ->execute();
+ ->execute()
+ ;
$this->startRecruiter();
@@ -35,8 +37,10 @@ public function testWorkerKillItselfAfterAMemoryLeakButNotAfterABigMemoryConsump
->until(function () {
$at = T\now();
$statistics = $this->recruiter->statistics($tag = null, $at);
- return $statistics['jobs']['queued'] == 0;
- });
+
+ return 0 == $statistics['jobs']['queued'];
+ })
+ ;
$numberOfWorkersCurrently = $this->numberOfWorkers();
@@ -49,14 +53,14 @@ public function testWorkerKillItselfAfterAMemoryLeakButNotAfterABigMemoryConsump
$this->assertEquals(
$numberOfExpectedWorkers,
$numberOfWorkersCurrently,
- "The number of workers before was $numberOfWorkersBefore and now after starting 1 and execute a job we have $numberOfWorkersCurrently"
+ "The number of workers before was $numberOfWorkersBefore and now after starting 1 and execute a job we have $numberOfWorkersCurrently",
);
}
public static function provideMemoryConsumptions()
{
return [
- //legend: [$withMemoryLeak, $howManyItems, $memoryLimit, $expectedWorkerAlive],
+ // legend: [$withMemoryLeak, $howManyItems, $memoryLimit, $expectedWorkerAlive],
[false, 2000000, '20MB', true],
[true, 2000000, '20MB', false],
[true, 2000000, '128MB', true],
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
index fcb0feb9..3d11950e 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
@@ -2,7 +2,6 @@
namespace Recruiter\Acceptance;
-use Recruiter\Workable\FactoryMethodCommand;
use Recruiter\Workable\ThrowsFatalError;
class WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest extends BaseAcceptanceTestCase
@@ -21,7 +20,7 @@ public function testInCaseOfExceptionTheExitCodeOfWorkerProcessIsNotZero()
$worker = $this->startWorker();
$workerProcess = $worker[0];
$this->waitForNumberOfWorkersToBe(1);
- list ($assignments, $_) = $this->recruiter->assignJobsToWorkers();
+ [$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertEquals(1, count($assignments));
$this->waitForNumberOfWorkersToBe(0, $seconds = 10);
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
index 68d18a71..83996c13 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
@@ -17,7 +17,7 @@ public function testRetireAfterAskedToStop()
$this->assertEquals(
$numberOfWorkersBefore,
$numberOfWorkersCurrently,
- "The number of workers before was $numberOfWorkersBefore and now after starting and stopping 1 we have $numberOfWorkersCurrently"
+ "The number of workers before was $numberOfWorkersBefore and now after starting and stopping 1 we have $numberOfWorkersCurrently",
);
}
}
diff --git a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
index 85634cbd..cb1949d0 100644
--- a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
+++ b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
@@ -3,17 +3,17 @@
namespace Recruiter\Acceptance;
use Recruiter\Worker\Repository;
-use Recruiter\Recruiter;
class WorkerRepositoryTest extends BaseAcceptanceTestCase
{
private Repository $repository;
+
protected function setUp(): void
{
parent::setUp();
$this->repository = new Repository(
$this->recruiterDb,
- $this->recruiter
+ $this->recruiter,
);
}
diff --git a/spec/Recruiter/CleanerTest.php b/spec/Recruiter/CleanerTest.php
index 295875a0..d1d99c4c 100644
--- a/spec/Recruiter/CleanerTest.php
+++ b/spec/Recruiter/CleanerTest.php
@@ -2,12 +2,11 @@
namespace Recruiter;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+use Timeless as T;
use Timeless\Interval;
-use Timeless\Clock;
use Timeless\Moment;
-use Timeless as T;
class CleanerTest extends TestCase
{
@@ -25,7 +24,8 @@ protected function setUp(): void
$this->jobRepository = $this
->getMockBuilder('Recruiter\Job\Repository')
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
$this->cleaner = new Cleaner($this->jobRepository);
@@ -50,11 +50,12 @@ public function testDelegatesTheCleanupOfArchivedJobsToTheJobsRepository()
->expects($this->once())
->method('cleanArchived')
->with($expectedUpperLimit)
- ->will($this->returnValue($jobsCleaned = 10));
+ ->will($this->returnValue($jobsCleaned = 10))
+ ;
$this->assertEquals(
$jobsCleaned,
- $this->cleaner->cleanArchived($this->interval)
+ $this->cleaner->cleanArchived($this->interval),
);
}
}
diff --git a/spec/Recruiter/FactoryTest.php b/spec/Recruiter/FactoryTest.php
index ba94ff80..b59ac993 100644
--- a/spec/Recruiter/FactoryTest.php
+++ b/spec/Recruiter/FactoryTest.php
@@ -21,7 +21,7 @@ public function testShouldCreateAMongoDatabaseConnection()
{
$this->assertInstanceOf(
'MongoDB\Database',
- $this->creationOfDefaultMongoDb()
+ $this->creationOfDefaultMongoDb(),
);
}
@@ -38,7 +38,7 @@ public function testShouldOverwriteTheWriteConcernPassedInTheOptions()
[
'connectTimeoutMS' => 1000,
'w' => '0',
- ]
+ ],
);
$this->assertEquals('majority', $mongoDb->getWriteConcern()->getW());
@@ -51,7 +51,7 @@ private function creationOfDefaultMongoDb(): Database
[
'connectTimeoutMS' => 1000,
'w' => '0',
- ]
+ ],
);
}
}
diff --git a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
index 7998d92d..a89b6c6c 100644
--- a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
+++ b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
@@ -2,9 +2,8 @@
namespace Recruiter;
-use Exception;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Recruiter\Job\Repository;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -22,7 +21,8 @@ protected function setUp(): void
$this->repository = $this
->getMockBuilder(Repository::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
$this->listener = new ListenerSpy();
@@ -52,7 +52,6 @@ public function testFinalizableFailureMethodsAreCalledWhenJobFails(): void
$this->assertSame($exception, $calls[2][1]);
}
-
public function testFinalizableSuccessfullMethodsAreCalledWhenJobIsDone()
{
$workable = new FinalizableWorkable(function () {
@@ -98,6 +97,7 @@ public function __construct(callable $whatToDo, $listener)
public function execute()
{
$whatToDo = $this->whatToDo;
+
return $whatToDo();
}
@@ -106,17 +106,17 @@ public function afterSuccess()
$this->listener->methodWasCalled(__FUNCTION__);
}
- public function afterFailure(Exception $e)
+ public function afterFailure(\Exception $e)
{
$this->listener->methodWasCalled(__FUNCTION__, $e);
}
- public function afterLastFailure(Exception $e)
+ public function afterLastFailure(\Exception $e)
{
$this->listener->methodWasCalled(__FUNCTION__, $e);
}
- public function finalize(?Exception $e = null)
+ public function finalize(?\Exception $e = null)
{
$this->listener->methodWasCalled(__FUNCTION__, $e);
}
diff --git a/spec/Recruiter/Infrastructure/Memory/MemoryLimitTest.php b/spec/Recruiter/Infrastructure/Memory/MemoryLimitTest.php
index d552d154..75507e1d 100644
--- a/spec/Recruiter/Infrastructure/Memory/MemoryLimitTest.php
+++ b/spec/Recruiter/Infrastructure/Memory/MemoryLimitTest.php
@@ -1,4 +1,5 @@
'generic',
- 'tags' =>[
+ 'tags' => [
1 => 'billing-notification',
],
]);
@@ -21,7 +22,7 @@ public function testHasTagReturnsFalseWhenTheExportedJobDoesNotContainTheTag()
{
$event = new Event([
'group' => 'generic',
- 'tags' =>[
+ 'tags' => [
1 => 'billing-notification',
],
]);
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 772da5d4..7b6aacb3 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -1,4 +1,5 @@
repository->queued(
'generic',
T\now(),
- T\now()->before(T\hour(24))
- )
+ T\now()->before(T\hour(24)),
+ ),
);
}
@@ -94,7 +94,7 @@ public function testRecentHistory()
[
'throughput' => [
'value' => 3.0,
- 'value_per_second' => 3/60.0,
+ 'value_per_second' => 3 / 60.0,
],
'latency' => [
'average' => 5.0,
@@ -103,7 +103,7 @@ public function testRecentHistory()
'average' => 0.0,
],
],
- $this->repository->recentHistory()
+ $this->repository->recentHistory(),
);
}
@@ -115,12 +115,14 @@ public function testCountQueuedJobsGroupingByASpecificKeyword()
$workable1
->expects($this->any())
->method('export')
- ->will($this->returnValue(['seller' => 'seller1']));
+ ->will($this->returnValue(['seller' => 'seller1']))
+ ;
$workable2
->expects($this->any())
->method('export')
- ->will($this->returnValue(['seller' => 'seller2']));
+ ->will($this->returnValue(['seller' => 'seller2']))
+ ;
$job1 = $this->aJob($workable1);
$job2 = $this->aJob($workable2);
@@ -134,32 +136,32 @@ public function testCountQueuedJobsGroupingByASpecificKeyword()
'seller1' => '1',
'seller2' => '2',
],
- $this->repository->queuedGroupedBy('workable.parameters.seller', [])
+ $this->repository->queuedGroupedBy('workable.parameters.seller', []),
);
}
public function testGetDelayedScheduledJobs()
{
$workable1 = $this->workableMockWithCustomParameters([
- 'job1' => 'delayed_and_unpicked'
+ 'job1' => 'delayed_and_unpicked',
]);
$workable2 = $this->workableMockWithCustomParameters([
- 'job2' => 'delayed_and_unpicked'
+ 'job2' => 'delayed_and_unpicked',
]);
$workable3 = $this->workableMockWithCustomParameters([
- 'job3' => 'in_schedulation'
+ 'job3' => 'in_schedulation',
]);
$this->aJobToSchedule($this->aJob($workable1))->inBackground()->execute();
$this->aJobToSchedule($this->aJob($workable2))->inBackground()->execute();
$lowerLimit = $this->clock->now();
- $fiveHoursInSeconds = 5*60*60;
+ $fiveHoursInSeconds = 5 * 60 * 60;
$this->clock->driftForwardBySeconds($fiveHoursInSeconds);
$this->aJobToSchedule($this->aJob($workable3))->inBackground()->execute();
$jobs = $this->repository->delayedScheduledJobs($lowerLimit);
$jobsFounds = 0;
foreach ($jobs as $job) {
$this->assertEquals('delayed_and_unpicked', reset($job->export()['workable']['parameters']));
- $jobsFounds++;
+ ++$jobsFounds;
}
$this->assertEquals(2, $jobsFounds);
}
@@ -169,7 +171,7 @@ public function testCountDelayedScheduledJobs()
$this->aJobToSchedule($this->aJob())->inBackground()->execute();
$this->aJobToSchedule($this->aJob())->inBackground()->execute();
$lowerLimit = $this->clock->now();
- $twoHoursInSeconds = 2*60*60;
+ $twoHoursInSeconds = 2 * 60 * 60;
$this->clock->driftForwardBySeconds($twoHoursInSeconds);
$this->aJobToSchedule($this->aJob())->inBackground()->execute();
$this->assertEquals(2, $this->repository->countDelayedScheduledJobs($lowerLimit));
@@ -180,19 +182,19 @@ public function testCountRecentJobsWithManyAttempts()
$ed = $this->eventDispatcher;
$this->repository->archive($this->aJob()->beforeExecution($ed)->beforeExecution($ed)->afterExecution(42, $ed));
$this->clock->now();
- $threeHoursInSeconds = 3*60*60;
+ $threeHoursInSeconds = 3 * 60 * 60;
$this->clock->driftForwardBySeconds($threeHoursInSeconds);
$lowerLimit = $this->clock->now();
$this->repository->archive($this->aJob()->beforeExecution($ed)->beforeExecution($ed)->afterExecution(42, $ed));
$this->repository->archive($this->aJob()->beforeExecution($ed)->beforeExecution($ed)->afterExecution(42, $ed));
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$createdAt = $endedAt = $this->clock->now();
$this->repository->save($this->jobMockWithAttemptsAndCustomParameters($createdAt, $endedAt));
$this->repository->save($this->jobMockWithAttemptsAndCustomParameters($createdAt, $endedAt));
$this->aJobToSchedule($this->aJob())->inBackground()->execute();
$upperLimit = $this->clock->now();
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$createdAt = $endedAt = $this->clock->now();
$this->repository->archive($this->aJob()->beforeExecution($ed)->beforeExecution($ed)->afterExecution(42, $ed));
@@ -204,31 +206,31 @@ public function testGetRecentJobsWithManyAttempts()
{
$ed = $this->eventDispatcher;
$workable1 = $this->workableMockWithCustomParameters([
- 'job1' => 'many_attempts_and_archived_but_too_old'
+ 'job1' => 'many_attempts_and_archived_but_too_old',
]);
$workable2 = $this->workableMockWithCustomParameters([
- 'job2' => 'many_attempts_and_archived'
+ 'job2' => 'many_attempts_and_archived',
]);
$workable3 = $this->workableMockWithCustomParameters([
- 'job3' => 'many_attempts_and_archived'
+ 'job3' => 'many_attempts_and_archived',
]);
- $workable4 = [
- 'job4' => 'many_attempts_and_scheduled'
+ $workable4 = [
+ 'job4' => 'many_attempts_and_scheduled',
];
- $workable5 = [
- 'job5' => 'many_attempts_and_scheduled'
+ $workable5 = [
+ 'job5' => 'many_attempts_and_scheduled',
];
$workable6 = $this->workableMockWithCustomParameters([
- 'job6' => 'one_attempt_and_scheduled'
+ 'job6' => 'one_attempt_and_scheduled',
]);
$this->repository->archive($this->aJob($workable1)->beforeExecution($ed)->beforeExecution($ed)->afterExecution(42, $ed));
$this->clock->now();
- $threeHoursInSeconds = 3*60*60;
+ $threeHoursInSeconds = 3 * 60 * 60;
$this->clock->driftForwardBySeconds($threeHoursInSeconds);
$lowerLimit = $this->clock->now();
$this->repository->archive($this->aJob($workable2)->beforeExecution($ed)->beforeExecution($ed)->afterExecution(42, $ed));
$this->repository->archive($this->aJob($workable3)->beforeExecution($ed)->beforeExecution($ed)->afterExecution(42, $ed));
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$createdAt = $endedAt = $this->clock->now();
$this->repository->save($this->jobMockWithAttemptsAndCustomParameters($createdAt, $endedAt, $workable4));
@@ -240,9 +242,9 @@ public function testGetRecentJobsWithManyAttempts()
foreach ($jobs as $job) {
$this->assertMatchesRegularExpression(
'/many_attempts_and_archived|many_attempts_and_scheduled/',
- reset($job->export()['workable']['parameters'])
+ reset($job->export()['workable']['parameters']),
);
- $jobsFounds++;
+ ++$jobsFounds;
}
$this->assertEquals(4, $jobsFounds);
}
@@ -255,20 +257,20 @@ public function testCountSlowRecentJobs()
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
- $endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s'))
- )
+ $endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s')),
+ ),
);
$archivedJobSlowExpired = $this->aJob()->beforeExecution($ed);
$this->clock->driftForwardBySeconds($elapseTimeInSecondsBeforeJobsExecutionEnd);
$archivedJobSlowExpired->afterExecution(42, $ed);
- $threeHoursInSeconds = 3*60*60;
+ $threeHoursInSeconds = 3 * 60 * 60;
$this->clock->driftForwardBySeconds($threeHoursInSeconds);
$lowerLimit = $createdAt = $endedAt = $this->clock->now();
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
- $endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s'))
- )
+ $endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s')),
+ ),
);
$archivedJobSlow1 = $this->aJob()->beforeExecution($ed);
$this->clock->driftForwardBySeconds($elapseTimeInSecondsBeforeJobsExecutionEnd);
@@ -278,7 +280,7 @@ public function testCountSlowRecentJobs()
$this->clock->driftForwardBySeconds($elapseTimeInSecondsBeforeJobsExecutionEnd);
$archivedJobSlow2->afterExecution(42, $ed);
$this->repository->archive($archivedJobSlow2);
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$createdAt = $endedAt = $this->clock->now();
$archivedJobNotSlow = $this->aJob()->beforeExecution($ed)->afterExecution(42, $ed);
@@ -286,26 +288,26 @@ public function testCountSlowRecentJobs()
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
- $endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s'))
- )
+ $endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s')),
+ ),
);
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$upperLimit = $createdAt = $endedAt = $this->clock->now();
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
- $endedAt
- )
+ $endedAt,
+ ),
);
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$createdAt = $endedAt = $this->clock->now();
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
- $endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s'))
- )
+ $endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s')),
+ ),
);
$this->assertEquals(4, $this->repository->countSlowRecentJobs($lowerLimit, $upperLimit));
}
@@ -319,76 +321,76 @@ public function testGetSlowRecentJobs()
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
$endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s')),
- ['job_scheduled_old' => 'slow_jobs_scheduled_but_too_old']
- )
+ ['job_scheduled_old' => 'slow_jobs_scheduled_but_too_old'],
+ ),
);
$archivedJobSlowExpired = $this->aJob($this->workableMockWithCustomParameters([
- 'job_archived_old' => 'slow_job_archived_but_too_old'
- ]))->beforeExecution($ed);
+ 'job_archived_old' => 'slow_job_archived_but_too_old',
+ ]))->beforeExecution($ed);
$this->clock->driftForwardBySeconds($elapseTimeInSecondsBeforeJobsExecutionEnd);
$archivedJobSlowExpired->afterExecution(42, $ed);
- $threeHoursInSeconds = 3*60*60;
+ $threeHoursInSeconds = 3 * 60 * 60;
$this->clock->driftForwardBySeconds($threeHoursInSeconds);
$lowerLimit = $createdAt = $endedAt = $this->clock->now();
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
$endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s')),
- ['job1_scheduled' => 'slow_job_recent_scheduled']
- )
+ ['job1_scheduled' => 'slow_job_recent_scheduled'],
+ ),
);
$archivedJobSlow1 = $this->aJob($this->workableMockWithCustomParameters([
- 'job1_archived' => 'slow_job_recent_archived'
- ]))->beforeExecution($ed);
+ 'job1_archived' => 'slow_job_recent_archived',
+ ]))->beforeExecution($ed);
$archivedJobSlow2 = $this->aJob($this->workableMockWithCustomParameters([
- 'job2_archived' => 'slow_job_recent_archived'
- ]))->beforeExecution($ed);
+ 'job2_archived' => 'slow_job_recent_archived',
+ ]))->beforeExecution($ed);
$this->clock->driftForwardBySeconds($elapseTimeInSecondsBeforeJobsExecutionEnd);
$archivedJobSlow1->afterExecution(41, $ed);
$this->repository->archive($archivedJobSlow1);
$archivedJobSlow2->afterExecution(42, $ed);
$this->repository->archive($archivedJobSlow2);
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$createdAt = $endedAt = $this->clock->now();
$archivedJobNotSlow = $this->aJob($this->workableMockWithCustomParameters([
- 'job_archived' => 'job_archived_not_slow'
- ]))->beforeExecution($ed)->afterExecution(42, $ed);
+ 'job_archived' => 'job_archived_not_slow',
+ ]))->beforeExecution($ed)->afterExecution(42, $ed);
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
$endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s')),
- ['job2_scheduled' => 'slow_job_recent_scheduled']
- )
+ ['job2_scheduled' => 'slow_job_recent_scheduled'],
+ ),
);
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$upperLimit = $createdAt = $endedAt = $this->clock->now();
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
$endedAt,
- ['job_scheduled' => 'job_recent_scheduled_slow']
- )
+ ['job_scheduled' => 'job_recent_scheduled_slow'],
+ ),
);
- $oneHourInSeconds = 60*60;
+ $oneHourInSeconds = 60 * 60;
$this->clock->driftForwardBySeconds($oneHourInSeconds);
$createdAt = $endedAt = $this->clock->now();
$this->repository->save(
$this->jobMockWithAttemptsAndCustomParameters(
$createdAt,
$endedAt->after(Interval::parse($elapseTimeInSecondsBeforeJobsExecutionEnd . ' s')),
- ['job3_scheduled' => 'slow_job_recent_scheduled']
- )
+ ['job3_scheduled' => 'slow_job_recent_scheduled'],
+ ),
);
$jobs = $this->repository->slowRecentJobs($lowerLimit, $upperLimit);
$jobsFounds = 0;
foreach ($jobs as $job) {
$this->assertMatchesRegularExpression(
'/slow_job_recent_archived|slow_job_recent_scheduled/',
- reset($job->export()['workable']['parameters'])
+ reset($job->export()['workable']['parameters']),
);
- $jobsFounds++;
+ ++$jobsFounds;
}
$this->assertEquals(4, $jobsFounds);
}
@@ -422,7 +424,8 @@ private function aJob($workable = null)
}
return Job::around($workable, $this->repository)
- ->scheduleAt(T\now()->before(T\seconds(5)));
+ ->scheduleAt(T\now()->before(T\seconds(5)))
+ ;
}
private function aJobToSchedule($job = null)
@@ -438,7 +441,8 @@ private function workableMock()
{
return $this
->getMockBuilder('Recruiter\Workable')
- ->getMock();
+ ->getMock()
+ ;
}
private function workableMockWithCustomParameters($parameters)
@@ -447,7 +451,9 @@ private function workableMockWithCustomParameters($parameters)
$workable
->expects($this->any())
->method('export')
- ->will($this->returnValue($parameters));
+ ->will($this->returnValue($parameters))
+ ;
+
return $workable;
}
@@ -455,10 +461,12 @@ private function jobExecutionMock($executionParameters)
{
$jobExecutionMock = $this
->getMockBuilder('Recruiter\JobExecution')
- ->getMock();
+ ->getMock()
+ ;
$jobExecutionMock->expects($this->once())
->method('export')
- ->will($this->returnValue($executionParameters));
+ ->will($this->returnValue($executionParameters))
+ ;
return $jobExecutionMock;
}
@@ -466,23 +474,23 @@ private function jobExecutionMock($executionParameters)
private function jobMockWithAttemptsAndCustomParameters(
?Moment $createdAt = null,
?Moment $endedAt = null,
- ?array $workableParameters = null
+ ?array $workableParameters = null,
): Job&MockObject {
$parameters = [
'_id' => new ObjectId(),
'created_at' => T\MongoDate::from($createdAt),
- "done" => false,
- "attempts" => 10,
- "group" => "generic",
- "scheduled_at" => T\MongoDate::from($createdAt),
- "last_execution" => [
- "started_at" => T\MongoDate::from($createdAt),
- "ended_at" => T\MongoDate::from($endedAt)
+ 'done' => false,
+ 'attempts' => 10,
+ 'group' => 'generic',
+ 'scheduled_at' => T\MongoDate::from($createdAt),
+ 'last_execution' => [
+ 'started_at' => T\MongoDate::from($createdAt),
+ 'ended_at' => T\MongoDate::from($endedAt),
+ ],
+ 'retry_policy' => [
+ 'class' => 'Recruiter\\RetryPolicy\\DoNotDoItAgain',
+ 'parameters' => [],
],
- "retry_policy" => [
- "class" => "Recruiter\\RetryPolicy\\DoNotDoItAgain",
- "parameters" => []
- ]
];
if (!empty($workableParameters)) {
@@ -493,10 +501,12 @@ private function jobMockWithAttemptsAndCustomParameters(
$job = $this
->getMockBuilder(Job::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
$job->expects($this->once())
->method('export')
->willReturn($parameters);
+
return $job;
}
}
diff --git a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
index 580d9c9b..a71b8d94 100644
--- a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
+++ b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
@@ -2,9 +2,8 @@
namespace Recruiter;
-use Exception;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Recruiter\Job\Repository;
class JobCallCustomMethodOnWorkableTest extends TestCase
@@ -18,12 +17,14 @@ protected function setUp(): void
$this->workable = $this
->getMockBuilder(Workable::class)
->setMethods(['export', 'import', 'asJobOf', 'send'])
- ->getMock();
+ ->getMock()
+ ;
$this->repository = $this
->getMockBuilder(Repository::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
$this->job = Job::around($this->workable, $this->repository);
}
@@ -37,7 +38,7 @@ public function testConfigureMethodToCallOnWorkable()
public function testRaiseExceptionWhenConfigureMethodToCallOnWorkableThatDoNotExists()
{
- $this->expectException(Exception::class);
+ $this->expectException(\Exception::class);
$this->job->methodToCallOnWorkable('methodThatDoNotExists');
}
diff --git a/spec/Recruiter/JobSendEventsToWorkableTest.php b/spec/Recruiter/JobSendEventsToWorkableTest.php
index ff778b6d..4bbb0c19 100644
--- a/spec/Recruiter/JobSendEventsToWorkableTest.php
+++ b/spec/Recruiter/JobSendEventsToWorkableTest.php
@@ -3,8 +3,8 @@
namespace Recruiter;
use PHPUnit\Framework\MockObject\Exception;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Recruiter\Job\Event;
use Recruiter\Job\EventListener;
use Recruiter\Job\Repository;
@@ -20,7 +20,8 @@ protected function setUp(): void
$this->repository = $this
->getMockBuilder(Repository::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
}
@@ -37,8 +38,9 @@ public function testTakeRetryPolicyFromRetriableInstance()
->withConsecutive(
[$this->equalTo('job.started'), $this->anything()],
[$this->equalTo('job.ended'), $this->anything()],
- [$this->equalTo('job.failure.last'), $this->anything()]
- );
+ [$this->equalTo('job.failure.last'), $this->anything()],
+ )
+ ;
$workable = new WorkableThatIsAlsoAnEventListener($listener);
$job = Job::around($workable, $this->repository);
diff --git a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
index 84f89dd6..e2939e21 100644
--- a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
+++ b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
@@ -3,12 +3,10 @@
namespace Recruiter;
use PHPUnit\Framework\MockObject\Exception;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Recruiter\Job\Repository;
use Recruiter\RetryPolicy\BaseRetryPolicy;
-use Timeless as T;
-use Recruiter\RetryPolicy;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class JobTakeRetryPolicyFromRetriableWorkableTest extends TestCase
@@ -21,7 +19,8 @@ protected function setUp(): void
$this->repository = $this
->getMockBuilder(Repository::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
$this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
}
diff --git a/spec/Recruiter/JobTest.php b/spec/Recruiter/JobTest.php
index c56a31dc..b419fc29 100644
--- a/spec/Recruiter/JobTest.php
+++ b/spec/Recruiter/JobTest.php
@@ -1,12 +1,12 @@
repository = $this
->getMockBuilder(Repository::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
}
public function testRetryStatisticsOnFirstExecution()
{
- $job = Job::around(new AlwaysFail, $this->repository);
+ $job = Job::around(new AlwaysFail(), $this->repository);
$retryStatistics = $job->retryStatistics();
$this->assertIsArray($retryStatistics);
$this->assertArrayHasKey('job_id', $retryStatistics);
@@ -38,7 +39,7 @@ public function testRetryStatisticsOnFirstExecution()
*/
public function testRetryStatisticsOnSubsequentExecutions()
{
- $job = Job::around(new AlwaysFail, $this->repository);
+ $job = Job::around(new AlwaysFail(), $this->repository);
// maybe make the argument optional
$job->execute($this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'));
$job = Job::import($job->export(), $this->repository);
@@ -53,14 +54,14 @@ public function testRetryStatisticsOnSubsequentExecutions()
$this->assertArrayHasKey('message', $lastExecution);
$this->assertArrayHasKey('trace', $lastExecution);
$this->assertEquals("Sorry, I'm good for nothing", $lastExecution['message']);
- $this->assertMatchesRegularExpression("/.*AlwaysFail->execute.*/", $lastExecution['trace']);
+ $this->assertMatchesRegularExpression('/.*AlwaysFail->execute.*/', $lastExecution['trace']);
}
public function testArrayAsGroupIsNotAllowed()
{
- $this->expectException(RuntimeException::class);
+ $this->expectException(\RuntimeException::class);
$memoryLimit = new MemoryLimit(1);
- $job = Job::around(new AlwaysFail, $this->repository);
+ $job = Job::around(new AlwaysFail(), $this->repository);
$job->inGroup(['test']);
}
}
diff --git a/spec/Recruiter/JobToBePassedRetryStatisticsTest.php b/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
index e54cf7a2..4f98057b 100644
--- a/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
+++ b/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
@@ -18,7 +18,8 @@ protected function setUp(): void
$this->repository = $this
->getMockBuilder(Repository::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
}
/**
@@ -30,7 +31,7 @@ public function testTakeRetryPolicyFromRetriableInstance()
$job = Job::around($workable, $this->repository);
$job->execute($this->createMock(EventDispatcherInterface::class));
- $this->assertTrue($job->done(), "Job requiring retry statistics was not executed correctly: " . var_export($job->export(), true));
+ $this->assertTrue($job->done(), 'Job requiring retry statistics was not executed correctly: ' . var_export($job->export(), true));
}
}
diff --git a/spec/Recruiter/JobToScheduleTest.php b/spec/Recruiter/JobToScheduleTest.php
index 36fc6ff5..b81c8afb 100644
--- a/spec/Recruiter/JobToScheduleTest.php
+++ b/spec/Recruiter/JobToScheduleTest.php
@@ -2,11 +2,9 @@
namespace Recruiter;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Timeless as T;
-use Timeless\Clock;
-use Recruiter\RetryPolicy;
class JobToScheduleTest extends TestCase
{
@@ -19,7 +17,8 @@ protected function setUp(): void
$this->job = $this
->getMockBuilder(Job::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
}
protected function tearDown(): void
@@ -33,12 +32,14 @@ public function testInBackgroundShouldScheduleJobNow()
->expects($this->once())
->method('scheduleAt')
->with(
- $this->equalTo($this->clock->now())
- );
+ $this->equalTo($this->clock->now()),
+ )
+ ;
(new JobToSchedule($this->job))
->inBackground()
- ->execute();
+ ->execute()
+ ;
}
public function testScheduledInShouldScheduleInCertainAmountOfTime()
@@ -48,12 +49,14 @@ public function testScheduledInShouldScheduleInCertainAmountOfTime()
->expects($this->once())
->method('scheduleAt')
->with(
- $this->equalTo($amountOfTime->fromNow())
- );
+ $this->equalTo($amountOfTime->fromNow()),
+ )
+ ;
(new JobToSchedule($this->job))
->scheduleIn($amountOfTime)
- ->execute();
+ ->execute()
+ ;
}
public function testConfigureRetryPolicy()
@@ -63,12 +66,14 @@ public function testConfigureRetryPolicy()
$this->job
->expects($this->once())
->method('retryWithPolicy')
- ->with($doNotDoItAgain);
+ ->with($doNotDoItAgain)
+ ;
(new JobToSchedule($this->job))
->inBackground()
->retryWithPolicy($doNotDoItAgain)
- ->execute();
+ ->execute()
+ ;
}
public function tesShortcutToConfigureJobToNotBeRetried()
@@ -76,43 +81,51 @@ public function tesShortcutToConfigureJobToNotBeRetried()
$this->job
->expects($this->once())
->method('retryWithPolicy')
- ->with($this->isInstanceOf('Recruiter\RetryPolicy\DoNotDoItAgain'));
+ ->with($this->isInstanceOf('Recruiter\RetryPolicy\DoNotDoItAgain'))
+ ;
(new JobToSchedule($this->job))
->inBackground()
->doNotRetry()
- ->execute();
+ ->execute()
+ ;
}
public function testShouldNotExecuteJobWhenScheduled()
{
$this->job
->expects($this->once())
- ->method('save');
+ ->method('save')
+ ;
$this->job
->expects($this->never())
- ->method('execute');
+ ->method('execute')
+ ;
(new JobToSchedule($this->job))
->inBackground()
- ->execute();
+ ->execute()
+ ;
}
public function testShouldExecuteJobWhenNotScheduled()
{
$this->job
->expects($this->never())
- ->method('scheduleAt');
+ ->method('scheduleAt')
+ ;
$this->job
->expects($this->once())
- ->method('execute');
+ ->method('execute')
+ ;
(new JobToSchedule($this->job))
->execute(
- $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface')
- );
+ $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'),
+ )
+ ;
}
public function testConfigureMethodToCallOnWorkableInJob()
@@ -120,10 +133,12 @@ public function testConfigureMethodToCallOnWorkableInJob()
$this->job
->expects($this->once())
->method('methodToCallOnWorkable')
- ->with('send');
+ ->with('send')
+ ;
(new JobToSchedule($this->job))
- ->send();
+ ->send()
+ ;
}
public function testReturnsJobId()
@@ -131,14 +146,15 @@ public function testReturnsJobId()
$this->job
->expects($this->any())
->method('id')
- ->will($this->returnValue('42'));
+ ->will($this->returnValue('42'))
+ ;
$this->assertEquals(
'42',
(new JobToSchedule($this->job))
->execute(
- $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface')
- )
+ $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'),
+ ),
);
}
}
diff --git a/spec/Recruiter/PickAvailableWorkersTest.php b/spec/Recruiter/PickAvailableWorkersTest.php
index 7c54d84f..54abd630 100644
--- a/spec/Recruiter/PickAvailableWorkersTest.php
+++ b/spec/Recruiter/PickAvailableWorkersTest.php
@@ -2,11 +2,10 @@
namespace Recruiter;
-use ArrayIterator;
use MongoDB\BSON\ObjectId;
use MongoDB\Collection;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
class PickAvailableWorkersTest extends TestCase
{
@@ -18,7 +17,8 @@ protected function setUp(): void
$this->repository = $this
->getMockBuilder(Collection::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
$this->workersPerUnit = 42;
}
@@ -39,7 +39,7 @@ public function testFewWorkersWithNoSpecifiSkill()
$picked = Worker::pickAvailableWorkers($this->repository, $this->workersPerUnit);
- list ($worksOn, $workers) = $picked[0];
+ [$worksOn, $workers] = $picked[0];
$this->assertEquals('*', $worksOn);
$this->assertEquals(3, count($workers));
}
@@ -51,7 +51,7 @@ public function testFewWorkersWithSameSkill()
$picked = Worker::pickAvailableWorkers($this->repository, $this->workersPerUnit);
- list ($worksOn, $workers) = $picked[0];
+ [$worksOn, $workers] = $picked[0];
$this->assertEquals('send-emails', $worksOn);
$this->assertEquals(3, count($workers));
}
@@ -64,7 +64,7 @@ public function testFewWorkersWithSomeDifferentSkills()
$allSkillsGiven = [];
$totalWorkersGiven = 0;
foreach ($picked as $pickedRow) {
- list ($worksOn, $workers) = $pickedRow;
+ [$worksOn, $workers] = $pickedRow;
$allSkillsGiven[] = $worksOn;
$totalWorkersGiven += count($workers);
}
@@ -80,7 +80,7 @@ public function testMoreWorkersThanAllowedPerUnit()
$totalWorkersGiven = 0;
foreach ($picked as $pickedRow) {
- list ($worksOn, $workers) = $pickedRow;
+ [$worksOn, $workers] = $pickedRow;
$totalWorkersGiven += count($workers);
}
$this->assertEquals($this->workersPerUnit, $totalWorkersGiven);
@@ -90,11 +90,11 @@ private function withAvailableWorkers($workers)
{
$workersThatShouldBeFound = [];
foreach ($workers as $skill => $quantity) {
- for ($counter = 0; $counter < $quantity; $counter++) {
+ for ($counter = 0; $counter < $quantity; ++$counter) {
$workerId = new ObjectId();
- $workersThatShouldBeFound[(string)$workerId] = [
+ $workersThatShouldBeFound[(string) $workerId] = [
'_id' => $workerId,
- 'work_on' => $skill
+ 'work_on' => $skill,
];
}
}
@@ -102,7 +102,8 @@ private function withAvailableWorkers($workers)
$this->repository
->expects($this->any())
->method('find')
- ->will($this->returnValue(new ArrayIterator($workersThatShouldBeFound)));
+ ->will($this->returnValue(new \ArrayIterator($workersThatShouldBeFound)))
+ ;
}
private function withNoAvailableWorkers()
@@ -110,7 +111,8 @@ private function withNoAvailableWorkers()
$this->repository
->expects($this->any())
->method('find')
- ->will($this->returnValue(new ArrayIterator([])));
+ ->will($this->returnValue(new \ArrayIterator([])))
+ ;
}
private function assertArrayAreEquals($expected, $given)
diff --git a/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php b/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
index fa451aad..102c100a 100644
--- a/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
+++ b/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
@@ -1,4 +1,5 @@
expects($this->once())
->method('scheduleIn')
- ->with(T\seconds(5));
+ ->with(T\seconds(5))
+ ;
$retryPolicy->schedule($job);
}
@@ -24,7 +26,8 @@ public function testAfterEachFailureDoublesTheAmountOfTimeToWaitBetweenRetries()
$job->expects($this->once())
->method('scheduleIn')
- ->with(T\seconds(10));
+ ->with(T\seconds(10))
+ ;
$retryPolicy->schedule($job);
}
@@ -35,7 +38,8 @@ public function testAfterTooManyFailuresGivesUp()
$job->expects($this->once())
->method('archive')
- ->with('tried-too-many-times');
+ ->with('tried-too-many-times')
+ ;
$retryPolicy->schedule($job);
}
@@ -43,7 +47,7 @@ public function testCanBeCreatedByTargetingAMaximumInterval()
{
$this->assertEquals(
ExponentialBackoff::forAnInterval(1025, T\seconds(1)),
- new ExponentialBackoff(10, 1)
+ new ExponentialBackoff(10, 1),
);
}
@@ -52,7 +56,9 @@ private function jobExecutedFor($times)
$job = $this->getMockBuilder('Recruiter\JobAfterFailure')->disableOriginalConstructor()->getMock();
$job->expects($this->any())
->method('numberOfAttempts')
- ->will($this->returnValue($times));
+ ->will($this->returnValue($times))
+ ;
+
return $job;
}
}
diff --git a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
index bffbd9e8..13ccdfd7 100644
--- a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
+++ b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
@@ -2,10 +2,8 @@
namespace Recruiter\RetryPolicy;
-use Exception;
-use InvalidArgumentException;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Recruiter\RetryPolicy;
class RetriableExceptionFilterTest extends TestCase
@@ -22,40 +20,43 @@ protected function setUp(): void
public function testCallScheduleOnRetriableException()
{
- $exception = $this->createMock(Exception::class);
+ $exception = $this->createMock(\Exception::class);
$classOfException = get_class($exception);
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
$this->filteredRetryPolicy
->expects($this->once())
- ->method('schedule');
+ ->method('schedule')
+ ;
$filter->schedule($this->jobFailedWithException($exception));
}
public function testDoNotCallScheduleOnNonRetriableException()
{
- $exception = $this->createMock(Exception::class);
+ $exception = $this->createMock(\Exception::class);
$classOfException = get_class($exception);
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
$this->filteredRetryPolicy
->expects($this->never())
- ->method('schedule');
+ ->method('schedule')
+ ;
- $filter->schedule($this->jobFailedWithException(new Exception('Test')));
+ $filter->schedule($this->jobFailedWithException(new \Exception('Test')));
}
public function testWhenExceptionIsNotRetriableThenArchiveTheJob()
{
- $exception = $this->createMock(Exception::class);
+ $exception = $this->createMock(\Exception::class);
$classOfException = get_class($exception);
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
- $job = $this->jobFailedWithException(new Exception('Test'));
+ $job = $this->jobFailedWithException(new \Exception('Test'));
$job->expects($this->once())
->method('archive')
- ->with('non-retriable-exception');
+ ->with('non-retriable-exception')
+ ;
$filter->schedule($job);
}
@@ -64,10 +65,11 @@ public function testAllExceptionsAreRetriableByDefault()
{
$this->filteredRetryPolicy
->expects($this->once())
- ->method('schedule');
+ ->method('schedule')
+ ;
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy);
- $filter->schedule($this->jobFailedWithException(new Exception('Test')));
+ $filter->schedule($this->jobFailedWithException(new \Exception('Test')));
}
public function testJobFailedWithSomethingThatIsNotAnException()
@@ -75,7 +77,8 @@ public function testJobFailedWithSomethingThatIsNotAnException()
$jobAfterFailure = $this->jobFailedWithException(null);
$jobAfterFailure
->expects($this->once())
- ->method('archive');
+ ->method('archive')
+ ;
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy);
$filter->schedule($jobAfterFailure);
@@ -86,19 +89,20 @@ public function testExportFilteredRetryPolicy()
$this->filteredRetryPolicy
->expects($this->once())
->method('export')
- ->will($this->returnValue(['key' => 'value']));
+ ->will($this->returnValue(['key' => 'value']))
+ ;
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy);
$this->assertEquals(
[
'retriable_exceptions' => ['Exception'],
- 'filtered_retry_policy' => [
+ 'filtered_retry_policy' => [
'class' => get_class($this->filteredRetryPolicy),
- 'parameters' => ['key' => 'value']
- ]
+ 'parameters' => ['key' => 'value'],
+ ],
],
- $filter->export()
+ $filter->export(),
);
}
@@ -109,27 +113,27 @@ public function testImportRetryPolicy()
$exported = $filter->export();
$filter = RetriableExceptionFilter::import($exported);
- $filter->schedule($this->jobFailedWithException(new Exception('Test')));
+ $filter->schedule($this->jobFailedWithException(new \Exception('Test')));
$this->assertEquals($exported, $filter->export());
}
public function testRetriableExceptionsThatAreNotExceptions()
{
- $this->expectException(InvalidArgumentException::class);
+ $this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage("Only subclasses of Exception can be retriable exceptions, 'StdClass' is not");
$retryPolicy = new DoNotDoItAgain();
$notAnExceptionClass = 'StdClass';
new RetriableExceptionFilter($retryPolicy, [$notAnExceptionClass]);
}
-
private function jobFailedWithException($exception)
{
$jobAfterFailure = $this
->getMockBuilder('Recruiter\JobAfterFailure')
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
$jobAfterFailure
->expects($this->any())
diff --git a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
index 06e272bf..91f62db4 100644
--- a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
+++ b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
@@ -1,9 +1,7 @@
when(InvalidArgumentException::class)->then(new DoNotDoItAgain())
- ->when(LogicException::class)->then(new DoNotDoItAgain())
- ->build();
+ ->when(\InvalidArgumentException::class)->then(new DoNotDoItAgain())
+ ->when(\LogicException::class)->then(new DoNotDoItAgain())
+ ->build()
+ ;
$this->assertInstanceOf(RetryPolicy::class, $retryPolicy);
}
@@ -23,9 +22,10 @@ public function testCanBeBuilt()
public function testCanBeExportedAndImported()
{
$retryPolicy = SelectByException::create()
- ->when(InvalidArgumentException::class)->then(new DoNotDoItAgain())
- ->when(LogicException::class)->then(new DoNotDoItAgain())
- ->build();
+ ->when(\InvalidArgumentException::class)->then(new DoNotDoItAgain())
+ ->when(\LogicException::class)->then(new DoNotDoItAgain())
+ ->build()
+ ;
$retryPolicyExported = $retryPolicy->export();
$retryPolicyImported = SelectByException::import($retryPolicyExported);
@@ -36,24 +36,25 @@ public function testCanBeExportedAndImported()
public function testSelectByException()
{
- $exception = new InvalidArgumentException('something');
+ $exception = new \InvalidArgumentException('something');
$retryPolicy = new SelectByException([
- new RetriableException(get_class($exception), RetryForever::afterSeconds(10))
+ new RetriableException(get_class($exception), RetryForever::afterSeconds(10)),
]);
$job = $this->jobFailedWith($exception);
$job->expects($this->once())
->method('scheduleIn')
- ->with(T\seconds(10));
+ ->with(T\seconds(10))
+ ;
$retryPolicy->schedule($job);
}
public function testDefaultDoNotSchedule()
{
- $exception = new Exception('something');
+ $exception = new \Exception('something');
$retryPolicy = new SelectByException([
- new RetriableException(InvalidArgumentException::class, RetryForever::afterSeconds(10))
+ new RetriableException(\InvalidArgumentException::class, RetryForever::afterSeconds(10)),
]);
$job = $this->jobFailedWith($exception);
@@ -63,12 +64,14 @@ public function testDefaultDoNotSchedule()
$retryPolicy->schedule($job);
}
- private function jobFailedWith(Exception $exception)
+ private function jobFailedWith(\Exception $exception)
{
$job = $this->getMockBuilder('Recruiter\JobAfterFailure')->disableOriginalConstructor()->getMock();
$job->expects($this->any())
->method('causeOfFailure')
- ->will($this->returnValue($exception));
+ ->will($this->returnValue($exception))
+ ;
+
return $job;
}
}
diff --git a/spec/Recruiter/RetryPolicy/TimeTableTest.php b/spec/Recruiter/RetryPolicy/TimeTableTest.php
index dd93d037..2ce8ea2e 100644
--- a/spec/Recruiter/RetryPolicy/TimeTableTest.php
+++ b/spec/Recruiter/RetryPolicy/TimeTableTest.php
@@ -2,7 +2,6 @@
namespace Recruiter\RetryPolicy;
-use Exception;
use PHPUnit\Framework\TestCase;
use Timeless as T;
@@ -26,7 +25,8 @@ public function testShouldRescheduleInOneMinuteWhenWasCreatedLessThanFiveMinutes
$job = $this->givenJobThat($wasCreatedAt);
$job->expects($this->once())
->method('scheduleAt')
- ->with($this->equalTo($expectedToBeScheduledAt));
+ ->with($this->equalTo($expectedToBeScheduledAt))
+ ;
$this->scheduler->schedule($job);
}
@@ -37,7 +37,8 @@ public function testShouldRescheduleInFiveMinutesWhenWasCreatedLessThanOneHourAg
$job = $this->givenJobThat($wasCreatedAt);
$job->expects($this->once())
->method('scheduleAt')
- ->with($this->equalTo($expectedToBeScheduledAt));
+ ->with($this->equalTo($expectedToBeScheduledAt))
+ ;
$this->scheduler->schedule($job);
}
@@ -48,7 +49,8 @@ public function testShouldRescheduleInFiveMinutesWhenWasCreatedLessThan24HoursAg
$job = $this->givenJobThat($wasCreatedAt);
$job->expects($this->once())
->method('scheduleAt')
- ->with($this->equalTo($expectedToBeScheduledAt));
+ ->with($this->equalTo($expectedToBeScheduledAt))
+ ;
$this->scheduler->schedule($job);
}
@@ -64,7 +66,8 @@ public function testIsLastRetryReturnTrueIfJobWasCreatedMoreThanLastTimeSpen()
$job = $this->createMock('Recruiter\Job');
$job->expects($this->any())
->method('createdAt')
- ->will($this->returnValue(T\hours(3)->ago()));
+ ->will($this->returnValue(T\hours(3)->ago()))
+ ;
$tt = new TimeTable([
'1 minute ago' => '1 minute',
@@ -78,30 +81,31 @@ public function testIsLastRetryReturnFalseIfJobWasCreatedLessThanLastTimeSpen()
$job = $this->createMock('Recruiter\Job');
$job->expects($this->any())
->method('createdAt')
- ->will($this->returnValue(T\hours(3)->ago()));
+ ->will($this->returnValue(T\hours(3)->ago()))
+ ;
$tt = new TimeTable([
'1 hour ago' => '1 minute',
- '24 hours ago' => '1 minute'
+ '24 hours ago' => '1 minute',
]);
$this->assertFalse($tt->isLastRetry($job));
}
public function testInvalidTimeTableBecauseTimeWindow()
{
- $this->expectException(Exception::class);
+ $this->expectException(\Exception::class);
$tt = new TimeTable(['1 minute' => '1 second']);
}
public function testInvalidTimeTableBecauseRescheduleTime()
{
- $this->expectException(Exception::class);
+ $this->expectException(\Exception::class);
$tt = new TimeTable(['1 minute ago' => '1 second ago']);
}
public function testInvalidTimeTableBecauseRescheduleTimeIsGreaterThanTimeWindow()
{
- $this->expectException(Exception::class);
+ $this->expectException(\Exception::class);
$tt = new TimeTable(['1 minute ago' => '2 minutes']);
}
@@ -110,10 +114,13 @@ private function givenJobThat(T\Moment $wasCreatedAt)
$job = $this->getMockBuilder('Recruiter\JobAfterFailure')
->disableOriginalConstructor()
->setMethods(['createdAt', 'scheduleAt'])
- ->getMock();
+ ->getMock()
+ ;
$job->expects($this->any())
->method('createdAt')
- ->will($this->returnValue($wasCreatedAt));
+ ->will($this->returnValue($wasCreatedAt))
+ ;
+
return $job;
}
@@ -123,10 +130,12 @@ private function jobThatWasCreated($relativeTime)
$job = $this->getMockBuilder('Recruiter\JobAfterFailure')
->disableOriginalConstructor()
->setMethods(['createdAt', 'scheduleAt'])
- ->getMock();
+ ->getMock()
+ ;
$job->expects($this->any())
->method('createdAt')
->will($this->returnValue($wasCreatedAt));
+
return $job;
}
}
diff --git a/spec/Recruiter/SchedulePolicy/CronTest.php b/spec/Recruiter/SchedulePolicy/CronTest.php
index 51dece3b..bac7a8cf 100644
--- a/spec/Recruiter/SchedulePolicy/CronTest.php
+++ b/spec/Recruiter/SchedulePolicy/CronTest.php
@@ -2,7 +2,6 @@
namespace Recruiter\SchedulePolicy;
-use DateTime;
use PHPUnit\Framework\TestCase;
use Timeless\Moment;
@@ -13,13 +12,13 @@ class CronTest extends TestCase
*/
public function testCronCanBeExportedAndImportedWithoutDataLoss(string $cronExpression, string $expectedDate)
{
- $cron = new Cron($cronExpression, DateTime::createFromFormat('Y-m-d H:i:s', '2019-01-15 15:00:00'));
+ $cron = new Cron($cronExpression, \DateTime::createFromFormat('Y-m-d H:i:s', '2019-01-15 15:00:00'));
$cron = Cron::import($cron->export());
$this->assertEquals(
- Moment::fromDateTime(new DateTime($expectedDate)),
+ Moment::fromDateTime(new \DateTime($expectedDate)),
$cron->next(),
- 'calculated schedule time is: ' . $cron->next()->format()
+ 'calculated schedule time is: ' . $cron->next()->format(),
);
}
diff --git a/spec/Recruiter/TaggableWorkableTest.php b/spec/Recruiter/TaggableWorkableTest.php
index ee85fea5..c6ead3f8 100644
--- a/spec/Recruiter/TaggableWorkableTest.php
+++ b/spec/Recruiter/TaggableWorkableTest.php
@@ -2,11 +2,9 @@
namespace Recruiter;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Recruiter\Job\Repository;
-use Timeless as T;
-use Recruiter\Taggable;
class TaggableWorkableTest extends TestCase
{
@@ -17,7 +15,8 @@ protected function setUp(): void
$this->repository = $this
->getMockBuilder(Repository::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
}
public function testWorkableExportsTags()
diff --git a/spec/Recruiter/WaitStrategyTest.php b/spec/Recruiter/WaitStrategyTest.php
index 909aa0a9..4ff7a53e 100644
--- a/spec/Recruiter/WaitStrategyTest.php
+++ b/spec/Recruiter/WaitStrategyTest.php
@@ -15,8 +15,8 @@ class WaitStrategyTest extends TestCase
protected function setUp(): void
{
$this->waited = T\milliseconds(0);
- $this->howToWait = function($microseconds): void {
- $this->waited = T\milliseconds($microseconds/1000);
+ $this->howToWait = function ($microseconds): void {
+ $this->waited = T\milliseconds($microseconds / 1000);
};
$this->timeToWaitAtLeast = T\milliseconds(250);
$this->timeToWaitAtMost = T\seconds(30);
@@ -27,7 +27,7 @@ public function testStartsToWaitTheMinimumAmountOfTime()
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
$this->timeToWaitAtMost,
- $this->howToWait
+ $this->howToWait,
);
$ws->wait();
$this->assertEquals($this->timeToWaitAtLeast, $this->waited);
@@ -38,7 +38,7 @@ public function testBackingOffIncreasesTheIntervalExponentially()
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
$this->timeToWaitAtMost,
- $this->howToWait
+ $this->howToWait,
);
$ws->wait();
$this->assertEquals($this->timeToWaitAtLeast, $this->waited);
@@ -64,7 +64,7 @@ public function testGoingForwardLowersTheSleepingPeriod()
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
$this->timeToWaitAtMost,
- $this->howToWait
+ $this->howToWait,
);
$ws->backOff();
$ws->goForward();
@@ -77,7 +77,7 @@ public function testTheSleepingPeriodCanBeResetToTheMinimum()
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
$this->timeToWaitAtMost,
- $this->howToWait
+ $this->howToWait,
);
$ws->backOff();
$ws->backOff();
@@ -93,7 +93,7 @@ public function testGoingForwardCannotLowerTheIntervalBelowMinimum()
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
$this->timeToWaitAtMost,
- $this->howToWait
+ $this->howToWait,
);
$ws->goForward();
$ws->goForward();
diff --git a/spec/Recruiter/Workable/FactoryMethodCommandTest.php b/spec/Recruiter/Workable/FactoryMethodCommandTest.php
index 508e3991..b7263e2d 100644
--- a/spec/Recruiter/Workable/FactoryMethodCommandTest.php
+++ b/spec/Recruiter/Workable/FactoryMethodCommandTest.php
@@ -1,4 +1,5 @@
myObject()
- ->myMethod('answer', 42);
+ ->myMethod('answer', 42)
+ ;
$this->assertEquals('42', $workable->execute());
}
@@ -17,10 +19,11 @@ public function testCanBeImportedAndExported()
{
$workable = FactoryMethodCommand::from('Recruiter\Workable\DummyFactory::create')
->myObject()
- ->myMethod('answer', 42);
+ ->myMethod('answer', 42)
+ ;
$this->assertEquals(
$workable,
- FactoryMethodCommand::import($workable->export())
+ FactoryMethodCommand::import($workable->export()),
);
}
@@ -28,7 +31,8 @@ public function testPassesRetryStatisticsAsAnAdditionalArgumentToTheLastMethodTo
{
$workable = FactoryMethodCommand::from('Recruiter\Workable\DummyFactory::create')
->myObject()
- ->myNeedyMethod();
+ ->myNeedyMethod()
+ ;
$this->assertEquals(2, $workable->execute(['retry_number' => 2]));
}
}
diff --git a/spec/Recruiter/Workable/ShellCommandTest.php b/spec/Recruiter/Workable/ShellCommandTest.php
index c2ad1bc8..2eba223f 100644
--- a/spec/Recruiter/Workable/ShellCommandTest.php
+++ b/spec/Recruiter/Workable/ShellCommandTest.php
@@ -1,4 +1,5 @@
assertEquals(
$workable,
- ShellCommand::import($workable->export())
+ ShellCommand::import($workable->export()),
);
}
}
diff --git a/spec/Recruiter/WorkablePersistenceTest.php b/spec/Recruiter/WorkablePersistenceTest.php
index 95fba471..ac8e3e71 100644
--- a/spec/Recruiter/WorkablePersistenceTest.php
+++ b/spec/Recruiter/WorkablePersistenceTest.php
@@ -11,7 +11,7 @@ public function testCanBeExportedAndImported()
$job = new SomethingWorkable(['key' => 'value']);
$this->assertEquals(
$job,
- SomethingWorkable::import($job->export())
+ SomethingWorkable::import($job->export()),
);
}
}
diff --git a/spec/Recruiter/WorkerProcessTest.php b/spec/Recruiter/WorkerProcessTest.php
index df9c1b30..f3d7bfdd 100644
--- a/spec/Recruiter/WorkerProcessTest.php
+++ b/spec/Recruiter/WorkerProcessTest.php
@@ -2,8 +2,8 @@
namespace Recruiter;
-use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Recruiter\Worker\Process;
use Recruiter\Worker\Repository;
use Sink\BlackHole;
@@ -19,7 +19,8 @@ protected function setUp(): void
$this->repository = $this->getMockBuilder(Repository::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMock()
+ ;
}
public function testIfNotAliveWhenIsNotAliveReturnsItself()
@@ -39,7 +40,8 @@ public function testRetireWorkerIfNotAlive()
$this->repository
->expects($this->once())
->method('retireWorkerWithPid')
- ->with($this->pid);
+ ->with($this->pid)
+ ;
$process = $this->givenWorkerProcessDead();
$process->cleanUp($this->repository);
@@ -50,13 +52,13 @@ public function testDoNotRetireWorkerIfAlive()
$this->repository
->expects($this->never())
->method('retireWorkerWithPid')
- ->with($this->pid);
+ ->with($this->pid)
+ ;
$process = $this->givenWorkerProcessAlive();
$process->cleanUp($this->repository);
}
-
private function givenWorkerProcessAlive()
{
return $this->givenWorkerProcess(true);
@@ -72,11 +74,13 @@ private function givenWorkerProcess($alive)
$process = $this->getMockBuilder('Recruiter\Worker\Process')
->setMethods(['isAlive'])
->setConstructorArgs([$this->pid])
- ->getMock();
+ ->getMock()
+ ;
$process->expects($this->any())
->method('isAlive')
- ->will($this->returnValue($alive));
+ ->will($this->returnValue($alive))
+ ;
return $process;
}
diff --git a/spec/Sink/BlackHoleTest.php b/spec/Sink/BlackHoleTest.php
index 82867707..097ec792 100644
--- a/spec/Sink/BlackHoleTest.php
+++ b/spec/Sink/BlackHoleTest.php
@@ -60,7 +60,7 @@ public function testIsAccessibleAsAnArrayAlwaysGetItself()
$instance = new BlackHole();
$this->assertInstanceOf('Sink\BlackHole', $instance[42]);
$this->assertInstanceOf('Sink\BlackHole', $instance['aString']);
- $this->assertInstanceOf('Sink\BlackHole', $instance[[1,2,3]]);
+ $this->assertInstanceOf('Sink\BlackHole', $instance[[1, 2, 3]]);
}
/* public function testIsAccessibleAsAnArrayExists() */
diff --git a/spec/Timeless/IntervalParseTest.php b/spec/Timeless/IntervalParseTest.php
index c3f8f210..8cc384f4 100644
--- a/spec/Timeless/IntervalParseTest.php
+++ b/spec/Timeless/IntervalParseTest.php
@@ -2,7 +2,6 @@
namespace Timeless;
-use DateInterval;
use PHPUnit\Framework\TestCase;
class IntervalParseTest extends TestCase
@@ -88,9 +87,9 @@ public function testParseShortFormat()
public function testFromDateInterval()
{
- $this->assertEquals(days(2), Interval::fromDateInterval(new DateInterval('P2D')));
- $this->assertEquals(minutes(10), Interval::fromDateInterval(new DateInterval('PT10M')));
- $this->assertEquals(days(2)->add(minutes(10)), Interval::fromDateInterval(new DateInterval('P2DT10M')));
+ $this->assertEquals(days(2), Interval::fromDateInterval(new \DateInterval('P2D')));
+ $this->assertEquals(minutes(10), Interval::fromDateInterval(new \DateInterval('PT10M')));
+ $this->assertEquals(days(2)->add(minutes(10)), Interval::fromDateInterval(new \DateInterval('P2DT10M')));
}
public function testNumberAsIntervalFormat()
diff --git a/spec/Timeless/MongoDateTest.php b/spec/Timeless/MongoDateTest.php
index baecddf2..a7095a37 100644
--- a/spec/Timeless/MongoDateTest.php
+++ b/spec/Timeless/MongoDateTest.php
@@ -1,4 +1,5 @@
forAll(
- Generator\choose(0, 1500 * 1000 * 1000)
+ Generator\choose(0, 1500 * 1000 * 1000),
)
->then(function ($milliseconds): void {
$moment = new Moment($milliseconds);
$this->assertEquals(
$moment,
- MongoDate::toMoment(MongoDate::from($moment))
+ MongoDate::toMoment(MongoDate::from($moment)),
);
- });
+ })
+ ;
}
}
diff --git a/src/Recruiter/AlreadyRunningException.php b/src/Recruiter/AlreadyRunningException.php
index a534409a..172e4bd2 100644
--- a/src/Recruiter/AlreadyRunningException.php
+++ b/src/Recruiter/AlreadyRunningException.php
@@ -2,8 +2,6 @@
namespace Recruiter;
-use Exception;
-
-class AlreadyRunningException extends Exception
+class AlreadyRunningException extends \Exception
{
}
diff --git a/src/Recruiter/CannotRetireWorkerAtWorkException.php b/src/Recruiter/CannotRetireWorkerAtWorkException.php
index 452d5359..5e7864cd 100644
--- a/src/Recruiter/CannotRetireWorkerAtWorkException.php
+++ b/src/Recruiter/CannotRetireWorkerAtWorkException.php
@@ -1,8 +1,7 @@
addArgument(
'shell_command',
InputArgument::REQUIRED,
- 'The command to run'
+ 'The command to run',
)
;
}
@@ -33,7 +34,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
ShellCommand::fromCommandLine($input->getArgument('shell_command'))
->asJobOf($this->recruiter)
->inBackground()
- ->execute();
+ ->execute()
+ ;
return self::SUCCESS;
}
diff --git a/src/Recruiter/Factory.php b/src/Recruiter/Factory.php
index ddf73c86..d8164685 100644
--- a/src/Recruiter/Factory.php
+++ b/src/Recruiter/Factory.php
@@ -5,7 +5,6 @@
use MongoDB\Client;
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
use Recruiter\Infrastructure\Persistence\Mongodb\URI;
-use UnexpectedValueException;
class Factory
{
@@ -22,19 +21,13 @@ public function getMongoDb(URI $uri, array $options = [])
'document' => 'array',
'root' => 'array',
],
- ], $options)
+ ], $options),
);
$client->listDatabases(); // in order to avoid lazy connections and catch eventually connection exceptions here
+
return $client->selectDatabase($uri->database());
} catch (DriverRuntimeException $e) {
- throw new UnexpectedValueException(
- sprintf(
- "'No MongoDB running at '%s'",
- $uri->__toString()
- ),
- $e->getCode(),
- $e
- );
+ throw new \UnexpectedValueException(sprintf("'No MongoDB running at '%s'", $uri->__toString()), $e->getCode(), $e);
}
}
}
diff --git a/src/Recruiter/Finalizable.php b/src/Recruiter/Finalizable.php
index ccdec82d..6804f06c 100644
--- a/src/Recruiter/Finalizable.php
+++ b/src/Recruiter/Finalizable.php
@@ -1,17 +1,16 @@
addOption(
'group',
'g',
InputOption::VALUE_REQUIRED,
- 'limit analytics to a specific job group'
+ 'limit analytics to a specific job group',
)
;
}
@@ -72,7 +68,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
->setRows([array_values($analytic)])
;
- for ($i = 0; $i < count($analytic); $i++) {
+ for ($i = 0; $i < count($analytic); ++$i) {
$table->setColumnStyle($i, $rightAligned);
$table->setColumnWidth($i, $columnsWidth);
}
diff --git a/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php b/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
index 6ec828e7..ff6b894f 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
@@ -1,9 +1,9 @@
addOption(
'scheduleAt',
's',
InputOption::VALUE_REQUIRED,
- 're-scheduling the job at specific datetime'
+ 're-scheduling the job at specific datetime',
)
->addArgument(
'jobId',
InputArgument::REQUIRED,
- 'the id of the job in archived collection to be recovered'
+ 'the id of the job in archived collection to be recovered',
)
;
}
@@ -80,14 +74,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($input->getOption('scheduleAt')) {
/** @var string */
$scheduleAt = $input->getOption('scheduleAt');
- $job->scheduleAt(Moment::fromDateTime(new DateTime($scheduleAt)));
+ $job->scheduleAt(Moment::fromDateTime(new \DateTime($scheduleAt)));
} else {
$job->scheduleAt(T\now());
}
$job
->scheduledBy('recovering-archived-job', $archivedJobId, -1)
- ->save();
+ ->save()
+ ;
$output->writeln("Job recovered, new job id is `{$job->id()}`");
diff --git a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
index 70add3e9..6cfca252 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
@@ -1,4 +1,5 @@
buildOutputData();
if (!$outputData) {
$output->writeln('There are no schedulers yet.');
+
return self::SUCCESS;
}
@@ -99,7 +92,7 @@ private function selectUrnToDelete(array $urns, InputInterface $input, OutputInt
$question = new ChoiceQuestion(
'Please select the scheduler which you want delete',
$urns,
- null
+ null,
);
$question->setErrorMessage('scheduler %s is invalid.');
@@ -137,7 +130,7 @@ protected function buildOutputData()
$i = 0;
$schedulers = $this->schedulerRepository->all();
- if (! $schedulers) {
+ if (!$schedulers) {
return null;
}
@@ -146,7 +139,7 @@ protected function buildOutputData()
$info = [
'createdAt' => $data['created_at']->toDateTime()->format('c'),
- 'lastScheduling' => ($data['last_scheduling']['scheduled_at'])->toDateTime()->format('c'),
+ 'lastScheduling' => $data['last_scheduling']['scheduled_at']->toDateTime()->format('c'),
'workable' => $data['job']['workable']['class'],
'policy' => $scheduler->schedulePolicy()->export(),
];
@@ -166,7 +159,7 @@ protected function buildOutputData()
}
$outputData[] = [
- '' => "" . $i++ . "",
+ '' => '' . $i++ . '',
'urn' => $data['urn'],
'info' => $infoString,
];
diff --git a/src/Recruiter/Infrastructure/Command/CleanerCommand.php b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
index 302d5b71..a7ce29f6 100644
--- a/src/Recruiter/Infrastructure/Command/CleanerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
@@ -1,28 +1,27 @@
factory = $factory;
@@ -84,7 +80,7 @@ public function execute(): bool
$this->log(sprintf(
'[%s] cleaned up %d old jobs from the archive' . PHP_EOL,
$memoryUsage->format(),
- $numberOfJobsCleaned
+ $numberOfJobsCleaned,
), LogLevel::INFO);
$this->log(sprintf('going to sleep for %sms', $this->waitStrategy->current()), LogLevel::DEBUG);
@@ -94,9 +90,10 @@ public function execute(): bool
return $numberOfJobsCleaned > 0;
}
- public function shutdown(?Throwable $e = null): bool
+ public function shutdown(?\Throwable $e = null): bool
{
$this->log('ok, see you space cowboy...', LogLevel::INFO);
+
return true;
}
@@ -128,6 +125,7 @@ public function description(): string
public function definition(): InputDefinition
{
$defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
+
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('clean-after', 'c', InputOption::VALUE_REQUIRED, 'delete jobs after :period', '5days'),
@@ -147,7 +145,7 @@ public function init(InputInterface $input): void
$this->waitStrategy = new ExponentialBackoffStrategy(
Interval::parse($input->getOption('wait-at-least'))->ms(),
- Interval::parse($input->getOption('wait-at-most'))->ms()
+ Interval::parse($input->getOption('wait-at-most'))->ms(),
);
$this->memoryLimit = new MemoryLimit($input->getOption('memory-limit'));
$this->gracePeriod = Interval::parse($input->getOption('clean-after'));
@@ -169,7 +167,7 @@ private function log(string $message, string $level = LogLevel::DEBUG): void
'program' => $this->name(),
'datetime' => date('c'),
'pid' => posix_getpid(),
- ]
+ ],
);
}
}
diff --git a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
index 61f97b95..ee06dd98 100644
--- a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
+++ b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
@@ -1,11 +1,14 @@
factory = $factory;
@@ -102,7 +96,7 @@ private function rollbackLockedJobs()
private function assignJobsToWorkers(): array
{
$pickStartAt = microtime(true);
- list($assignment, $actualNumber) = $this->recruiter->assignJobsToWorkers();
+ [$assignment, $actualNumber] = $this->recruiter->assignJobsToWorkers();
$pickEndAt = microtime(true);
foreach ($assignment as $worker => $job) {
$this->log(sprintf(' tried to assign job `%s` to worker `%s`', $job, $worker), LogLevel::INFO);
@@ -114,7 +108,7 @@ private function assignJobsToWorkers(): array
$memoryUsage->format(),
count($assignment),
($pickEndAt - $pickStartAt) * 1000,
- $actualNumber
+ $actualNumber,
), LogLevel::DEBUG);
$this->memoryLimit->ensure($memoryUsage);
@@ -128,27 +122,27 @@ private function scheduleRepeatableJobs(): void
$this->recruiter->scheduleRepeatableJobs();
$creationEndAt = microtime(true);
- //FIXME:! log every job created?
+ // FIXME:! log every job created?
/* foreach ($assignment as $worker => $job) { */
/* $this->log(sprintf(' tried to assign job `%s` to worker `%s`', $job, $worker)); */
/* } */
$this->log(sprintf(
'creation of jobs from crontab in %fms',
- ($creationEndAt - $creationStartAt) * 1000
+ ($creationEndAt - $creationStartAt) * 1000,
));
}
private function retireDeadWorkers()
{
$unlockedJobs = $this->recruiter->retireDeadWorkers(
- new DateTimeImmutable(),
- $this->consideredDeadAfter
+ new \DateTimeImmutable(),
+ $this->consideredDeadAfter,
);
$this->log(sprintf('unlocked %d jobs due to dead workers', $unlockedJobs), LogLevel::DEBUG);
}
- public function shutdown(?Throwable $e = null): bool
+ public function shutdown(?\Throwable $e = null): bool
{
$this->recruiter->bye();
$this->log('ok, see you space cowboy...', LogLevel::INFO);
@@ -184,6 +178,7 @@ public function description(): string
public function definition(): InputDefinition
{
$defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
+
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling (milliseconds)', '1600ms'),
@@ -207,7 +202,7 @@ public function init(InputInterface $input): void
$this->waitStrategy = new ExponentialBackoffStrategy(
Interval::parse($input->getOption('backoff-from'))->ms(),
- Interval::parse($input->getOption('backoff-to'))->ms()
+ Interval::parse($input->getOption('backoff-to'))->ms(),
);
$this->consideredDeadAfter = Interval::parse($input->getOption('considered-dead-after'));
@@ -234,7 +229,7 @@ private function log(string $message, string $level = LogLevel::DEBUG): void
'program' => $this->name(),
'datetime' => date('c'),
'pid' => posix_getpid(),
- ]
+ ],
);
}
diff --git a/src/Recruiter/Infrastructure/Command/WorkerCommand.php b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
index 626091e0..85447cb9 100644
--- a/src/Recruiter/Infrastructure/Command/WorkerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
@@ -1,21 +1,20 @@
factory = $factory;
@@ -81,7 +76,7 @@ public function execute(): bool
return (bool) $doneSomeWork;
}
- public function shutdown(?Throwable $e = null): bool
+ public function shutdown(?\Throwable $e = null): bool
{
if ($this->worker->retireIfNotAssigned()) {
$this->log(sprintf('worker `%s` retired', $this->worker->id()), LogLevel::INFO);
@@ -120,6 +115,7 @@ public function description(): string
public function definition(): InputDefinition
{
$defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
+
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling', '6400ms'),
@@ -139,7 +135,7 @@ public function init(InputInterface $input): void
$this->waitStrategy = new ExponentialBackoffStrategy(
Interval::parse($input->getOption('backoff-from'))->ms(),
- Interval::parse($input->getOption('backoff-to'))->ms()
+ Interval::parse($input->getOption('backoff-to'))->ms(),
);
$memoryLimit = new MemoryLimit($input->getOption('memory-limit'));
@@ -171,7 +167,7 @@ private function log(string $message, string $level = LogLevel::DEBUG): void
'datetime' => date('c'),
'pid' => posix_getpid(),
'workerId' => (string) $this->worker->id(),
- ]
+ ],
);
}
diff --git a/src/Recruiter/Infrastructure/Filesystem/BootstrapFile.php b/src/Recruiter/Infrastructure/Filesystem/BootstrapFile.php
index 9f12e88b..68cf7cab 100644
--- a/src/Recruiter/Infrastructure/Filesystem/BootstrapFile.php
+++ b/src/Recruiter/Infrastructure/Filesystem/BootstrapFile.php
@@ -1,13 +1,13 @@
filePath = $this->validate($filePath);
}
- public static function fromFilePath(string $filePath): Self
+ public static function fromFilePath(string $filePath): self
{
- return new Static($filePath);
+ return new static($filePath);
}
public function load(Recruiter $recruiter)
@@ -38,7 +38,7 @@ private function validate($filePath): string
}
if (!is_readable($filePath)) {
- $this->throwBecauseFile($filePath, "is not readable");
+ $this->throwBecauseFile($filePath, 'is not readable');
}
return $filePath;
@@ -46,12 +46,6 @@ private function validate($filePath): string
private function throwBecauseFile($filePath, $reason)
{
- throw new UnexpectedValueException(
- sprintf(
- "Bootstrap file has an invalid value: file '%s' %s",
- $filePath,
- $reason
- )
- );
+ throw new \UnexpectedValueException(sprintf("Bootstrap file has an invalid value: file '%s' %s", $filePath, $reason));
}
}
diff --git a/src/Recruiter/Infrastructure/Memory/MemoryLimit.php b/src/Recruiter/Infrastructure/Memory/MemoryLimit.php
index e59fd636..e04e05ab 100644
--- a/src/Recruiter/Infrastructure/Memory/MemoryLimit.php
+++ b/src/Recruiter/Infrastructure/Memory/MemoryLimit.php
@@ -1,13 +1,13 @@
limit = ByteUnits\parse($limit);
} catch (ByteUnits\ParseException $e) {
- throw new UnexpectedValueException(
- sprintf("Memory limit '%s' is an invalid value: %s", $limit, $e->getMessage())
- );
+ throw new \UnexpectedValueException(sprintf("Memory limit '%s' is an invalid value: %s", $limit, $e->getMessage()));
}
}
@@ -28,11 +26,7 @@ public function ensure($used)
{
$used = ByteUnits\box($used);
if ($used->isGreaterThan($this->limit)) {
- throw new MemoryLimitExceededException(sprintf(
- 'Memory limit reached, %s is more than the force limit of %s',
- $used->format(),
- $this->limit->format()
- ));
+ throw new MemoryLimitExceededException(sprintf('Memory limit reached, %s is more than the force limit of %s', $used->format(), $this->limit->format()));
}
}
}
diff --git a/src/Recruiter/Infrastructure/Memory/MemoryLimitExceededException.php b/src/Recruiter/Infrastructure/Memory/MemoryLimitExceededException.php
index 8188be2c..4516250a 100644
--- a/src/Recruiter/Infrastructure/Memory/MemoryLimitExceededException.php
+++ b/src/Recruiter/Infrastructure/Memory/MemoryLimitExceededException.php
@@ -1,9 +1,9 @@
retryWithPolicy() : new RetryPolicy\DoNotDoItAgain(),
new JobExecution(),
- $repository
+ $repository,
);
}
@@ -45,7 +39,7 @@ public static function import($document, Repository $repository)
WorkableInJob::import($document),
RetryPolicyInJob::import($document),
JobExecution::import($document),
- $repository
+ $repository,
);
}
@@ -76,6 +70,7 @@ public function numberOfAttempts()
public function retryWithPolicy(RetryPolicy $retryPolicy)
{
$this->retryPolicy = $retryPolicy;
+
return $this;
}
@@ -91,14 +86,13 @@ public function taggedAs(array $tags)
public function inGroup($group)
{
if (is_array($group)) {
- throw new RuntimeException(
- "Group can be only single string, for other uses use `taggedAs` method.
- Received group: `" . var_export($group, true) . "`"
- );
+ throw new \RuntimeException('Group can be only single string, for other uses use `taggedAs` method.
+ Received group: `' . var_export($group, true) . '`');
}
if (!empty($group)) {
$this->status['group'] = $group;
}
+
return $this;
}
@@ -106,12 +100,14 @@ public function scheduleAt(Moment $at)
{
$this->status['locked'] = false;
$this->status['scheduled_at'] = T\MongoDate::from($at);
+
return $this;
}
public function withUrn(string $urn)
{
$this->status['urn'] = $urn;
+
return $this;
}
@@ -131,7 +127,7 @@ public function scheduledBy(string $namespace, string $id, int $executions)
public function methodToCallOnWorkable($method)
{
if (!method_exists($this->workable, $method)) {
- throw new Exception("Unknown method '$method' on workable instance");
+ throw new \Exception("Unknown method '$method' on workable instance");
}
$this->status['workable']['method'] = $method;
}
@@ -145,7 +141,7 @@ public function execute(EventDispatcherInterface $eventDispatcher)
$result = $this->workable->$methodToCall($this->retryStatistics());
$this->afterExecution($result, $eventDispatcher);
}
- } catch (Throwable $exception) {
+ } catch (\Throwable $exception) {
$this->afterFailure($exception, $eventDispatcher);
}
@@ -184,19 +180,20 @@ public function export()
$this->lastJobExecution->export(),
$this->tagsToUseFor($this->workable),
WorkableInJob::export($this->workable, $this->status['workable']['method']),
- RetryPolicyInJob::export($this->retryPolicy)
+ RetryPolicyInJob::export($this->retryPolicy),
);
}
public function beforeExecution(EventDispatcherInterface $eventDispatcher)
{
- $this->status['attempts'] += 1;
+ ++$this->status['attempts'];
$this->lastJobExecution = new JobExecution();
$this->lastJobExecution->started($this->scheduledAt());
$this->emit('job.started', $eventDispatcher);
if ($this->hasBeenScheduled()) {
$this->save();
}
+
return $this;
}
@@ -209,6 +206,7 @@ public function afterExecution($result, EventDispatcherInterface $eventDispatche
if ($this->hasBeenScheduled()) {
$this->archive('done');
}
+
return $this;
}
@@ -222,6 +220,7 @@ private function recoverFromCrash(EventDispatcherInterface $eventDispatcher)
if ($this->lastJobExecution->isCrashed()) {
return !$archived = $this->afterFailure(new WorkerDiedInTheLineOfDutyException(), $eventDispatcher);
}
+
return true;
}
@@ -238,6 +237,7 @@ private function afterFailure($exception, $eventDispatcher)
$this->emit('job.failure.last', $eventDispatcher);
$this->triggerOnWorkable('afterLastFailure', $exception);
}
+
return $archived;
}
@@ -250,7 +250,7 @@ private function emit($eventType, EventDispatcherInterface $eventDispatcher): vo
}
}
- private function triggerOnWorkable($method, ?Throwable $e = null)
+ private function triggerOnWorkable($method, ?\Throwable $e = null)
{
if ($this->workable instanceof Finalizable) {
$this->workable->$method($e);
@@ -285,6 +285,7 @@ private function tagsToUseFor(Workable $workable)
if (!empty($tagsToUse)) {
return ['tags' => array_values(array_unique($tagsToUse))];
}
+
return [];
}
@@ -300,7 +301,7 @@ private static function initialize()
'group' => 'generic',
],
WorkableInJob::initialize(),
- RetryPolicyInJob::initialize()
+ RetryPolicyInJob::initialize(),
);
}
@@ -310,24 +311,23 @@ public static function pickReadyJobsForWorkers(MongoCollection $collection, $wor
iterator_to_array(
$collection
->find(
- (
- Worker::canWorkOnAnyJobs($worksOn) ?
- [ 'scheduled_at' => ['$lt' => T\MongoDate::now()],
- 'locked' => false,
- ] :
- [ 'scheduled_at' => ['$lt' => T\MongoDate::now()],
- 'locked' => false,
- 'group' => $worksOn,
- ]
- ),
+ Worker::canWorkOnAnyJobs($worksOn) ?
+ ['scheduled_at' => ['$lt' => T\MongoDate::now()],
+ 'locked' => false,
+ ] :
+ ['scheduled_at' => ['$lt' => T\MongoDate::now()],
+ 'locked' => false,
+ 'group' => $worksOn,
+ ]
+ ,
[
'projection' => ['_id' => 1],
'sort' => ['scheduled_at' => 1],
'limit' => count($workers),
- ]
- )
+ ],
+ ),
),
- '_id'
+ '_id',
);
if (count($jobs) > 0) {
@@ -347,13 +347,13 @@ public static function rollbackLockedNotIn(MongoCollection $collection, array $e
'$set' => [
'locked' => false,
'last_execution.crashed' => true,
- ]
- ]
+ ],
+ ],
);
return $result->getModifiedCount();
} catch (BulkWriteException $e) {
- throw new InvalidArgumentException("Not valid excluded jobs filter: " . var_export($excluded, true), -1, $e);
+ throw new \InvalidArgumentException('Not valid excluded jobs filter: ' . var_export($excluded, true), -1, $e);
}
}
@@ -361,7 +361,7 @@ public static function lockAll(MongoCollection $collection, $jobs)
{
$collection->updateMany(
['_id' => ['$in' => array_values($jobs)]],
- ['$set' => ['locked' => true]]
+ ['$set' => ['locked' => true]],
);
}
}
diff --git a/src/Recruiter/Job/Event.php b/src/Recruiter/Job/Event.php
index 094a0f3c..946d9489 100644
--- a/src/Recruiter/Job/Event.php
+++ b/src/Recruiter/Job/Event.php
@@ -1,4 +1,5 @@
jobExport) ? $this->jobExport['tags'] : [];
+
return in_array($wantedTag, $tags);
}
}
diff --git a/src/Recruiter/Job/Repository.php b/src/Recruiter/Job/Repository.php
index 169bda40..ef3dc499 100644
--- a/src/Recruiter/Job/Repository.php
+++ b/src/Recruiter/Job/Repository.php
@@ -1,12 +1,10 @@
map(
$this->scheduled->find([], [
'sort' => ['scheduled_at' => -1],
- ])
+ ]),
);
}
@@ -44,8 +42,8 @@ public function scheduled($id)
$found = $this->map($this->scheduled->find(['_id' => $id]));
- if (count($found) === 0) {
- throw new Exception("Unable to find scheduled job with ObjectId('{$id}')");
+ if (0 === count($found)) {
+ throw new \Exception("Unable to find scheduled job with ObjectId('{$id}')");
}
return $found[0];
@@ -59,8 +57,8 @@ public function archived($id)
$found = $this->map($this->archived->find(['_id' => $id]));
- if (count($found) === 0) {
- throw new Exception("Unable to find archived job with ObjectId('{$id}')");
+ if (0 === count($found)) {
+ throw new \Exception("Unable to find archived job with ObjectId('{$id}')");
}
return $found[0];
@@ -72,7 +70,7 @@ public function save(Job $job)
$this->scheduled->replaceOne(
['_id' => $document['_id']],
$document,
- ['upsert' => true]
+ ['upsert' => true],
);
}
@@ -87,7 +85,7 @@ public function releaseAll($jobIds)
{
$result = $this->scheduled->updateMany(
['_id' => ['$in' => $jobIds]],
- ['$set' => ['locked' => false, 'last_execution.crashed' => true]]
+ ['$set' => ['locked' => false, 'last_execution.crashed' => true]],
);
return $result->getModifiedCount();
@@ -104,15 +102,15 @@ public function cleanArchived(T\Moment $upperLimit)
[
'last_execution.ended_at' => [
'$lte' => T\MongoDate::from($upperLimit),
- ]
+ ],
],
- ['projection' => ['_id' => 1]]
+ ['projection' => ['_id' => 1]],
);
$deleted = 0;
foreach ($documents as $document) {
$this->archived->deleteOne(['_id' => $document['_id']]);
- $deleted++;
+ ++$deleted;
}
return $deleted;
@@ -123,7 +121,7 @@ public function cleanScheduled(T\Moment $upperLimit)
$result = $this->scheduled->deleteMany([
'created_at' => [
'$lte' => T\MongoDate::from($upperLimit),
- ]
+ ],
]);
return $result->getDeletedCount();
@@ -133,19 +131,19 @@ public function queued(
$group = null,
?T\Moment $at = null,
?T\Moment $from = null,
- array $query = []
+ array $query = [],
) {
- if ($at === null) {
+ if (null === $at) {
$at = T\now();
}
$query['scheduled_at']['$lte'] = T\MongoDate::from($at);
- if ($from !== null) {
+ if (null !== $from) {
$query['scheduled_at']['$gt'] = T\MongoDate::from($from);
}
- if ($group !== null) {
+ if (null !== $group) {
$query['group'] = $group;
}
@@ -154,13 +152,13 @@ public function queued(
public function postponed($group = null, ?T\Moment $at = null, array $query = [])
{
- if ($at === null) {
+ if (null === $at) {
$at = T\now();
}
$query['scheduled_at']['$gt'] = T\MongoDate::from($at);
- if ($group !== null) {
+ if (null !== $group) {
$query['group'] = $group;
}
@@ -169,7 +167,7 @@ public function postponed($group = null, ?T\Moment $at = null, array $query = []
public function scheduledCount($group = null, array $query = [])
{
- if ($group !== null) {
+ if (null !== $group) {
$query['group'] = $group;
}
@@ -179,7 +177,7 @@ public function scheduledCount($group = null, array $query = [])
public function queuedGroupedBy($field, array $query = [], $group = null)
{
$query['scheduled_at']['$lte'] = T\MongoDate::from(T\now());
- if ($group !== null) {
+ if (null !== $group) {
$query['group'] = $group;
}
@@ -201,7 +199,7 @@ public function queuedGroupedBy($field, array $query = [], $group = null)
public function recentHistory($group = null, ?T\Moment $at = null, array $query = [])
{
- if ($at === null) {
+ if (null === $at) {
$at = T\now();
}
$lastMinute = array_merge(
@@ -209,11 +207,11 @@ public function recentHistory($group = null, ?T\Moment $at = null, array $query
[
'last_execution.ended_at' => [
'$gt' => T\MongoDate::from($at->before(T\minute(1))),
- '$lte' => T\MongoDate::from($at)
+ '$lte' => T\MongoDate::from($at),
],
- ]
+ ],
);
- if ($group !== null) {
+ if (null !== $group) {
$lastMinute['group'] = $group;
}
$cursor = $this->archived->aggregate($pipeline = [
@@ -237,22 +235,22 @@ public function recentHistory($group = null, ?T\Moment $at = null, array $query
]);
$documents = $cursor->toArray();
- if (count($documents) === 0) {
+ if (0 === count($documents)) {
$throughputPerMinute = 0.0;
$averageLatency = 0.0;
$averageExecutionTime = 0;
- } elseif (count($documents) === 1) {
+ } elseif (1 === count($documents)) {
$throughputPerMinute = (float) $documents[0]['throughput'];
$averageLatency = $documents[0]['latency'] / 1000;
$averageExecutionTime = $documents[0]['execution_time'] / 1000;
} else {
- throw new RuntimeException("Result was not ok: " . var_export($documents, true));
+ throw new \RuntimeException('Result was not ok: ' . var_export($documents, true));
}
return [
'throughput' => [
'value' => $throughputPerMinute,
- 'value_per_second' => $throughputPerMinute/60.0,
+ 'value_per_second' => $throughputPerMinute / 60.0,
],
'latency' => [
'average' => $averageLatency,
@@ -266,35 +264,35 @@ public function recentHistory($group = null, ?T\Moment $at = null, array $query
public function countSlowRecentJobs(
T\Moment $lowerLimit,
T\Moment $upperLimit,
- $secondsToConsiderJobAsSlow = 5
+ $secondsToConsiderJobAsSlow = 5,
): int {
return count(
$this->slowArchivedRecentJobs(
$lowerLimit,
$upperLimit,
- $secondsToConsiderJobAsSlow
- )
+ $secondsToConsiderJobAsSlow,
+ ),
) + count(
$this->slowScheduledRecentJobs(
$lowerLimit,
$upperLimit,
- $secondsToConsiderJobAsSlow
- )
+ $secondsToConsiderJobAsSlow,
+ ),
);
}
public function countRecentJobsWithManyAttempts(
T\Moment $lowerLimit,
- T\Moment $upperLimit
+ T\Moment $upperLimit,
): int {
return $this->countRecentArchivedOrScheduledJobsWithManyAttempts(
$lowerLimit,
$upperLimit,
- 'archived'
+ 'archived',
) + $this->countRecentArchivedOrScheduledJobsWithManyAttempts(
$lowerLimit,
$upperLimit,
- 'scheduled'
+ 'scheduled',
);
}
@@ -302,8 +300,8 @@ public function countDelayedScheduledJobs(T\Moment $lowerLimit): int
{
return $this->scheduled->count([
'scheduled_at' => [
- '$lte' => T\MongoDate::from($lowerLimit)
- ]
+ '$lte' => T\MongoDate::from($lowerLimit),
+ ],
]);
}
@@ -312,63 +310,65 @@ public function delayedScheduledJobs(T\Moment $lowerLimit)
return $this->map(
$this->scheduled->find([
'scheduled_at' => [
- '$lte' => T\MongoDate::from($lowerLimit)
- ]
- ])
+ '$lte' => T\MongoDate::from($lowerLimit),
+ ],
+ ]),
);
}
public function recentJobsWithManyAttempts(
T\Moment $lowerLimit,
- T\Moment $upperLimit
+ T\Moment $upperLimit,
) {
$archived = $this->map(
$this->recentArchivedOrScheduledJobsWithManyAttempts(
$lowerLimit,
$upperLimit,
- 'archived'
- )
+ 'archived',
+ ),
);
$scheduled = $this->map(
$this->recentArchivedOrScheduledJobsWithManyAttempts(
$lowerLimit,
$upperLimit,
- 'scheduled'
- )
+ 'scheduled',
+ ),
);
+
return array_merge($archived, $scheduled);
}
public function slowRecentJobs(
T\Moment $lowerLimit,
T\Moment $upperLimit,
- $secondsToConsiderJobAsSlow = 5
+ $secondsToConsiderJobAsSlow = 5,
) {
- $archived= [];
+ $archived = [];
$archivedArray = $this->slowArchivedRecentJobs(
$lowerLimit,
$upperLimit,
- $secondsToConsiderJobAsSlow
+ $secondsToConsiderJobAsSlow,
);
foreach ($archivedArray as $archivedJob) {
$archived[] = Job::import($archivedJob, $this);
}
- $scheduled= [];
+ $scheduled = [];
$scheduledArray = $this->slowScheduledRecentJobs(
$lowerLimit,
$upperLimit,
- $secondsToConsiderJobAsSlow
+ $secondsToConsiderJobAsSlow,
);
foreach ($scheduledArray as $scheduledJob) {
$scheduled[] = Job::import($scheduledJob, $this);
}
+
return array_merge($archived, $scheduled);
}
private function slowArchivedRecentJobs(
T\Moment $lowerLimit,
T\Moment $upperLimit,
- $secondsToConsiderJobAsSlow
+ $secondsToConsiderJobAsSlow,
) {
return $this->archived->aggregate([
[
@@ -376,7 +376,7 @@ private function slowArchivedRecentJobs(
'last_execution.ended_at' => [
'$gte' => T\MongoDate::from($lowerLimit),
],
- ]
+ ],
],
[
'$project' => [
@@ -384,8 +384,8 @@ private function slowArchivedRecentJobs(
'execution_time' => [
'$subtract' => [
'$last_execution.ended_at',
- '$last_execution.started_at'
- ]
+ '$last_execution.started_at',
+ ],
],
'done' => '$done',
'created_at' => '$created_at',
@@ -397,13 +397,13 @@ private function slowArchivedRecentJobs(
'scheduled_at' => '$scheduled_at',
'last_execution' => '$last_execution',
'retry_policy' => '$retry_policy',
- ]
+ ],
],
[
'$match' => [
'execution_time' => [
- '$gt' => $secondsToConsiderJobAsSlow*1000
- ]
+ '$gt' => $secondsToConsiderJobAsSlow * 1000,
+ ],
],
],
])->toArray();
@@ -412,14 +412,14 @@ private function slowArchivedRecentJobs(
private function slowScheduledRecentJobs(
T\Moment $lowerLimit,
T\Moment $upperLimit,
- $secondsToConsiderJobAsSlow
+ $secondsToConsiderJobAsSlow,
) {
return $this->scheduled->aggregate([
[
'$match' => [
'scheduled_at' => [
'$gte' => T\MongoDate::from($lowerLimit),
- '$lte' => T\MongoDate::from($upperLimit)
+ '$lte' => T\MongoDate::from($upperLimit),
],
'last_execution.started_at' => [
'$exists' => true,
@@ -427,7 +427,7 @@ private function slowScheduledRecentJobs(
'last_execution.ended_at' => [
'$exists' => true,
],
- ]
+ ],
],
[
'$project' => [
@@ -435,8 +435,8 @@ private function slowScheduledRecentJobs(
'execution_time' => [
'$subtract' => [
'$last_execution.ended_at',
- '$last_execution.started_at'
- ]
+ '$last_execution.started_at',
+ ],
],
'done' => '$done',
'created_at' => '$created_at',
@@ -448,13 +448,13 @@ private function slowScheduledRecentJobs(
'scheduled_at' => '$scheduled_at',
'last_execution' => '$last_execution',
'retry_policy' => '$retry_policy',
- ]
+ ],
],
[
'$match' => [
'execution_time' => [
- '$gt' => $secondsToConsiderJobAsSlow*1000
- ]
+ '$gt' => $secondsToConsiderJobAsSlow * 1000,
+ ],
],
],
])->toArray();
@@ -463,28 +463,28 @@ private function slowScheduledRecentJobs(
private function countRecentArchivedOrScheduledJobsWithManyAttempts(
T\Moment $lowerLimit,
T\Moment $upperLimit,
- $collectionName
+ $collectionName,
) {
return count($this->recentArchivedOrScheduledJobsWithManyAttempts(
$lowerLimit,
$upperLimit,
- $collectionName
+ $collectionName,
)->toArray());
}
private function recentArchivedOrScheduledJobsWithManyAttempts(
T\Moment $lowerLimit,
T\Moment $upperLimit,
- $collectionName
+ $collectionName,
) {
return $this->{$collectionName}->find([
'last_execution.ended_at' => [
'$gte' => T\MongoDate::from($lowerLimit),
- '$lte' => T\MongoDate::from($upperLimit)
- ],
- 'attempts' => [
- '$gt' => 1
- ]
+ '$lte' => T\MongoDate::from($upperLimit),
+ ],
+ 'attempts' => [
+ '$gt' => 1,
+ ],
]);
}
diff --git a/src/Recruiter/JobAfterFailure.php b/src/Recruiter/JobAfterFailure.php
index 9f1d60e7..ba6fdd93 100644
--- a/src/Recruiter/JobAfterFailure.php
+++ b/src/Recruiter/JobAfterFailure.php
@@ -2,9 +2,8 @@
namespace Recruiter;
-use Timeless\Moment;
use Timeless\Interval;
-use Timeless\MongoDate;
+use Timeless\Moment;
class JobAfterFailure
{
@@ -76,8 +75,10 @@ public function archiveIfNotScheduled()
{
if (!$this->hasBeenScheduled && !$this->hasBeenArchived) {
$this->archive('not-scheduled-by-retry-policy');
+
return true;
}
+
return false;
}
diff --git a/src/Recruiter/JobExecution.php b/src/Recruiter/JobExecution.php
index 3e111d62..4c321b73 100644
--- a/src/Recruiter/JobExecution.php
+++ b/src/Recruiter/JobExecution.php
@@ -3,7 +3,6 @@
namespace Recruiter;
use Timeless as T;
-use Throwable;
class JobExecution
{
@@ -25,7 +24,7 @@ public function started($scheduledAt = null)
$this->startedAt = T\now();
}
- public function failedWith(Throwable $exception)
+ public function failedWith(\Throwable $exception)
{
$this->endedAt = T\now();
$this->failedWith = $exception;
@@ -57,9 +56,10 @@ public function duration()
if ($this->startedAt && $this->endedAt && ($this->startedAt <= $this->endedAt)) {
return T\seconds(
$this->endedAt->seconds() -
- $this->startedAt-> seconds()
+ $this->startedAt->seconds(),
);
}
+
return T\seconds(0);
}
@@ -78,6 +78,7 @@ public static function import($document)
$lastExecution->startedAt = T\MongoDate::toMoment($lastExecutionDocument['started_at']);
}
}
+
return $lastExecution;
}
@@ -111,7 +112,7 @@ public function export()
private function traceOf($result)
{
$trace = 'ok';
- if ($result instanceof Throwable) {
+ if ($result instanceof \Throwable) {
$trace = $result->getTraceAsString();
} elseif (is_object($result) && method_exists($result, 'trace')) {
$trace = $result->trace();
@@ -120,6 +121,7 @@ private function traceOf($result)
} elseif (is_string($result) || is_numeric($result)) {
$trace = $result;
}
+
return substr($trace, 0, 4096);
}
}
diff --git a/src/Recruiter/JobToSchedule.php b/src/Recruiter/JobToSchedule.php
index 880b209a..b6a21cff 100644
--- a/src/Recruiter/JobToSchedule.php
+++ b/src/Recruiter/JobToSchedule.php
@@ -2,8 +2,6 @@
namespace Recruiter;
-use Recruiter\Job;
-use Recruiter\RetryPolicy;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Timeless as T;
use Timeless\Interval;
@@ -32,9 +30,10 @@ public function retryManyTimes($howManyTimes, Interval $timeToWaitBeforeRetry, $
$this->job->retryWithPolicy(
$this->filterForRetriableExceptions(
new RetryPolicy\RetryManyTimes($howManyTimes, $timeToWaitBeforeRetry),
- $retriableExceptionTypes
- )
+ $retriableExceptionTypes,
+ ),
);
+
return $this;
}
@@ -43,9 +42,10 @@ public function retryWithPolicy(RetryPolicy $retryPolicy, $retriableExceptionTyp
$this->job->retryWithPolicy(
$this->filterForRetriableExceptions(
$retryPolicy,
- $retriableExceptionTypes
- )
+ $retriableExceptionTypes,
+ ),
);
+
return $this;
}
@@ -63,6 +63,7 @@ public function scheduleAt(Moment $momentInTime)
{
$this->mustBeScheduled = true;
$this->job->scheduleAt($momentInTime);
+
return $this;
}
@@ -105,6 +106,7 @@ public function execute()
} else {
$this->job->execute($this->emptyEventDispatcher());
}
+
return (string) $this->job->id();
}
@@ -116,6 +118,7 @@ private function emptyEventDispatcher()
public function __call($name, $arguments)
{
$this->job->methodToCallOnWorkable($name);
+
return $this->execute();
}
@@ -137,6 +140,7 @@ private function filterForRetriableExceptions($retryPolicy, $retriableExceptionT
if (!empty($retriableExceptionTypes)) {
$retryPolicy = new RetryPolicy\RetriableExceptionFilter($retryPolicy, $retriableExceptionTypes);
}
+
return $retryPolicy;
}
}
diff --git a/src/Recruiter/Recruiter.php b/src/Recruiter/Recruiter.php
index f9dea2e8..d1e58dff 100644
--- a/src/Recruiter/Recruiter.php
+++ b/src/Recruiter/Recruiter.php
@@ -1,13 +1,9 @@
jobs)
+ Job::around($workable, $this->jobs),
);
}
@@ -63,7 +59,7 @@ public function queuedGroupedBy($field, array $query = [], $group = null)
}
/**
- * @deprecated use the method `analytics` instead.
+ * @deprecated use the method `analytics` instead
*/
public function statistics($group = null, ?Moment $at = null, array $query = [])
{
@@ -84,7 +80,7 @@ public function analytics($group = null, ?Moment $at = null, array $query = [])
'zombies' => $totalsScheduledJobs - ($queued + $postponed),
],
],
- $this->jobs->recentHistory($group, $at, $query)
+ $this->jobs->recentHistory($group, $at, $query),
);
}
@@ -95,11 +91,13 @@ public function getEventDispatcher()
/**
* @step
- * @return integer how many
+ *
+ * @return int how many
*/
public function rollbackLockedJobs()
{
$assignedJobs = Worker::assignedJobs($this->db->selectCollection('roster'));
+
return Job::rollbackLockedNotIn($this->db->selectCollection('scheduled'), $assignedJobs);
}
@@ -134,17 +132,18 @@ public function bookJobsForWorkers()
$bookedJobs = [];
foreach (Worker::pickAvailableWorkers($roster, $workersPerUnit) as $resultRow) {
- list ($worksOn, $workers) = $resultRow;
+ [$worksOn, $workers] = $resultRow;
$result = Job::pickReadyJobsForWorkers($scheduled, $worksOn, $workers);
if ($result) {
- list($worksOn, $workers, $jobs) = $result;
- list($assignments, $jobs, $workers) = $this->combineJobsWithWorkers($jobs, $workers);
+ [$worksOn, $workers, $jobs] = $result;
+ [$assignments, $jobs, $workers] = $this->combineJobsWithWorkers($jobs, $workers);
Job::lockAll($scheduled, $jobs);
$bookedJobs[] = [$jobs, $workers];
}
}
+
return $bookedJobs;
}
@@ -157,14 +156,14 @@ public function assignLockedJobsToWorkers($bookedJobs)
$totalActualAssignments = 0;
$roster = $this->db->selectCollection('roster');
foreach ($bookedJobs as $row) {
- list ($jobs, $workers, ) = $row;
- list ($newAssignments, $actualAssignmentsNumber) = Worker::tryToAssignJobsToWorkers($roster, $jobs, $workers);
+ [$jobs, $workers] = $row;
+ [$newAssignments, $actualAssignmentsNumber] = Worker::tryToAssignJobsToWorkers($roster, $jobs, $workers);
if (array_intersect_key($assignments, $newAssignments)) {
- throw new RuntimeException("Conflicting assignments: current were " . var_export($assignments, true) . " and we want to also assign " . var_export($newAssignments, true));
+ throw new \RuntimeException('Conflicting assignments: current were ' . var_export($assignments, true) . ' and we want to also assign ' . var_export($newAssignments, true));
}
$assignments = array_merge(
$assignments,
- $newAssignments
+ $newAssignments,
);
$totalActualAssignments += $actualAssignmentsNumber;
}
@@ -173,7 +172,7 @@ public function assignLockedJobsToWorkers($bookedJobs)
array_map(function ($value) {
return (string) $value;
}, $assignments),
- $totalActualAssignments
+ $totalActualAssignments,
];
}
@@ -184,12 +183,13 @@ public function scheduledJob($id)
/**
* @step
- * @return integer how many jobs were unlocked as a result
+ *
+ * @return int how many jobs were unlocked as a result
*/
- public function retireDeadWorkers(DateTimeImmutable $now, Interval $consideredDeadAfter)
+ public function retireDeadWorkers(\DateTimeImmutable $now, Interval $consideredDeadAfter)
{
return $this->jobs->releaseAll(
- $jobsAssignedToDeadWorkers = Worker::retireDeadWorkers($this->workers, $now, $consideredDeadAfter)
+ $jobsAssignedToDeadWorkers = Worker::retireDeadWorkers($this->workers, $now, $consideredDeadAfter),
);
}
@@ -212,59 +212,59 @@ public function createCollectionsAndIndexes()
'locked' => 1,
'scheduled_at' => 1,
],
- ['background' => true]
+ ['background' => true],
);
$this->db->selectCollection('scheduled')->createIndex(
[
'locked' => 1,
'scheduled_at' => 1,
],
- ['background' => true]
+ ['background' => true],
);
$this->db->selectCollection('scheduled')->createIndex(
[
'locked' => 1,
],
- ['background' => true]
+ ['background' => true],
);
$this->db->selectCollection('scheduled')->createIndex(
[
'tags' => 1,
],
- ['background' => true, 'sparse' => true]
+ ['background' => true, 'sparse' => true],
);
$this->db->selectCollection('archived')->createIndex(
[
'created_at' => 1,
],
- ['background' => true]
+ ['background' => true],
);
$this->db->selectCollection('archived')->createIndex(
[
'created_at' => 1,
'group' => 1,
],
- ['background' => true]
+ ['background' => true],
);
$this->db->selectCollection('archived')->createIndex(
[
'last_execution.ended_at' => 1,
],
- ['background' => true]
+ ['background' => true],
);
$this->db->selectCollection('roster')->createIndex(
[
'available' => 1,
],
- ['background' => true]
+ ['background' => true],
);
$this->db->selectCollection('roster')->createIndex(
[
'last_seen_at' => 1,
],
- ['background' => true]
+ ['background' => true],
);
}
@@ -273,6 +273,7 @@ private function combineJobsWithWorkers($jobs, $workers)
$assignments = min(count($workers), count($jobs));
$workers = array_slice($workers, 0, $assignments);
$jobs = array_slice($jobs, 0, $assignments);
+
return [$assignments, $jobs, $workers];
}
}
diff --git a/src/Recruiter/Repeatable.php b/src/Recruiter/Repeatable.php
index 54a066d9..80cc6c0b 100644
--- a/src/Recruiter/Repeatable.php
+++ b/src/Recruiter/Repeatable.php
@@ -6,9 +6,7 @@ interface Repeatable extends Workable
{
/**
* Assign an unique name to the scheduler in order to handle idempotency,
- * only one scheduler with the same urn can exists
- *
- * @return string
+ * only one scheduler with the same urn can exists.
*/
public function urn(): string;
@@ -19,8 +17,6 @@ public function urn(): string;
*
* true: only one job at a time can be queued
* false: there may be more concurrent jobs at a time
- *
- * @return boolean
*/
public function unique(): bool;
}
diff --git a/src/Recruiter/RepeatableInJob.php b/src/Recruiter/RepeatableInJob.php
index 40f7af62..5546e4f8 100644
--- a/src/Recruiter/RepeatableInJob.php
+++ b/src/Recruiter/RepeatableInJob.php
@@ -1,8 +1,7 @@
self::classNameOf($workable),
'parameters' => $workable->export(),
'method' => $methodToCall,
- ]
+ ],
];
}
@@ -61,6 +60,7 @@ private static function classNameOf($repeatable): string
if (method_exists($repeatable, 'getClass')) {
$repeatableClassName = $repeatable->getClass();
}
+
return $repeatableClassName;
}
}
diff --git a/src/Recruiter/Retriable.php b/src/Recruiter/Retriable.php
index 89e3d369..67080a88 100644
--- a/src/Recruiter/Retriable.php
+++ b/src/Recruiter/Retriable.php
@@ -5,9 +5,7 @@
interface Retriable
{
/**
- * Declare what instance of `Recruiter\RetryPolicy` should be used for a `Recruiter\Workable`
- *
- * @return RetryPolicy
+ * Declare what instance of `Recruiter\RetryPolicy` should be used for a `Recruiter\Workable`.
*/
public function retryWithPolicy(): RetryPolicy;
}
diff --git a/src/Recruiter/RetryPolicy.php b/src/Recruiter/RetryPolicy.php
index 0c462c65..4acb51b5 100644
--- a/src/Recruiter/RetryPolicy.php
+++ b/src/Recruiter/RetryPolicy.php
@@ -7,36 +7,29 @@ interface RetryPolicy
/**
* Decide whether or not to reschedule a job. If you want to reschedule the
* job use the appropriate methods on job or do nothing to if you don't
- * want to execute the job again
+ * want to execute the job again.
*
* This method can
* - schedule the job
* - archive the job
* - do nothing (and the job will be archived anyway)
*
- * @param JobAfterFailure $job
- *
* @return void
*/
public function schedule(JobAfterFailure $job);
/**
- * Export retry policy parameters
- *
- * @return array
+ * Export retry policy parameters.
*/
public function export(): array;
/**
- * Import retry policy parameters
+ * Import retry policy parameters.
*
* @param array $parameters Previously exported parameters
- *
- * @return RetryPolicy
*/
public static function import(array $parameters): RetryPolicy;
-
/**
* @return bool true if is the last retry
*/
diff --git a/src/Recruiter/RetryPolicy/DoNotDoItAgain.php b/src/Recruiter/RetryPolicy/DoNotDoItAgain.php
index b7b28791..5ae8288a 100644
--- a/src/Recruiter/RetryPolicy/DoNotDoItAgain.php
+++ b/src/Recruiter/RetryPolicy/DoNotDoItAgain.php
@@ -3,9 +3,9 @@
namespace Recruiter\RetryPolicy;
use Recruiter\Job;
+use Recruiter\JobAfterFailure;
use Recruiter\RetryPolicy;
use Recruiter\RetryPolicyBehaviour;
-use Recruiter\JobAfterFailure;
class DoNotDoItAgain implements RetryPolicy
{
diff --git a/src/Recruiter/RetryPolicy/ExponentialBackoff.php b/src/Recruiter/RetryPolicy/ExponentialBackoff.php
index 4264dd68..9db868fc 100644
--- a/src/Recruiter/RetryPolicy/ExponentialBackoff.php
+++ b/src/Recruiter/RetryPolicy/ExponentialBackoff.php
@@ -3,20 +3,18 @@
namespace Recruiter\RetryPolicy;
use Recruiter\Job;
+use Recruiter\JobAfterFailure;
use Recruiter\RetryPolicy;
use Recruiter\RetryPolicyBehaviour;
-use Recruiter\JobAfterFailure;
-
use Timeless as T;
use Timeless\Interval;
class ExponentialBackoff implements RetryPolicy
{
+ use RetryPolicyBehaviour;
private $retryHowManyTimes;
private $timeToInitiallyWaitBeforeRetry;
- use RetryPolicyBehaviour;
-
public static function forTimes($retryHowManyTimes, $timeToInitiallyWaitBeforeRetry = 60)
{
return new static($retryHowManyTimes, $timeToInitiallyWaitBeforeRetry);
@@ -38,8 +36,9 @@ public static function forAnInterval($interval, $timeToInitiallyWaitBeforeRetry)
}
$numberOfRetries = round(
log($interval / $timeToInitiallyWaitBeforeRetry->seconds())
- / log(2)
+ / log(2),
);
+
return new static($numberOfRetries, $timeToInitiallyWaitBeforeRetry);
}
@@ -66,7 +65,7 @@ public function export(): array
{
return [
'retry_how_many_times' => $this->retryHowManyTimes,
- 'seconds_to_initially_wait_before_retry' => $this->timeToInitiallyWaitBeforeRetry->seconds()
+ 'seconds_to_initially_wait_before_retry' => $this->timeToInitiallyWaitBeforeRetry->seconds(),
];
}
@@ -74,7 +73,7 @@ public static function import(array $parameters): RetryPolicy
{
return new self(
$parameters['retry_how_many_times'],
- T\seconds($parameters['seconds_to_initially_wait_before_retry'])
+ T\seconds($parameters['seconds_to_initially_wait_before_retry']),
);
}
diff --git a/src/Recruiter/RetryPolicy/RetriableException.php b/src/Recruiter/RetryPolicy/RetriableException.php
index 59087f74..30546a73 100644
--- a/src/Recruiter/RetryPolicy/RetriableException.php
+++ b/src/Recruiter/RetryPolicy/RetriableException.php
@@ -1,9 +1,8 @@
exceptionClass = $exceptionClass;
$this->retryPolicy = $retryPolicy;
diff --git a/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php b/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
index 10a5913b..bc4e2203 100644
--- a/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
+++ b/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
@@ -2,11 +2,9 @@
namespace Recruiter\RetryPolicy;
-use InvalidArgumentException;
-
use Recruiter\Job;
-use Recruiter\RetryPolicy;
use Recruiter\JobAfterFailure;
+use Recruiter\RetryPolicy;
class RetriableExceptionFilter implements RetryPolicy
{
@@ -14,7 +12,8 @@ class RetriableExceptionFilter implements RetryPolicy
private $retriableExceptions;
/**
- * @param string $exceptionClass fully qualified class or interface name
+ * @param string $exceptionClass fully qualified class or interface name
+ *
* @return self
*/
public static function onlyFor($exceptionClass, RetryPolicy $retryPolicy)
@@ -43,8 +42,8 @@ public function export(): array
'retriable_exceptions' => $this->retriableExceptions,
'filtered_retry_policy' => [
'class' => get_class($this->filteredRetryPolicy),
- 'parameters' => $this->filteredRetryPolicy->export()
- ]
+ 'parameters' => $this->filteredRetryPolicy->export(),
+ ],
];
}
@@ -52,9 +51,10 @@ public static function import(array $parameters): RetryPolicy
{
$filteredRetryPolicy = $parameters['filtered_retry_policy'];
$retriableExceptions = $parameters['retriable_exceptions'];
+
return new self(
$filteredRetryPolicy['class']::import($filteredRetryPolicy['parameters']),
- $retriableExceptions
+ $retriableExceptions,
);
}
@@ -67,11 +67,10 @@ private function ensureAreAllExceptions($exceptions)
{
foreach ($exceptions as $exception) {
if (!is_a($exception, 'Throwable', true)) {
- throw new InvalidArgumentException(
- "Only subclasses of Exception can be retriable exceptions, '{$exception}' is not"
- );
+ throw new \InvalidArgumentException("Only subclasses of Exception can be retriable exceptions, '{$exception}' is not");
}
}
+
return $exceptions;
}
@@ -81,10 +80,11 @@ private function isExceptionRetriable($exception)
return array_any(
$this->retriableExceptions,
function ($retriableExceptionType) use ($exception) {
- return ($exception instanceof $retriableExceptionType);
- }
+ return $exception instanceof $retriableExceptionType;
+ },
);
}
+
return false;
}
}
diff --git a/src/Recruiter/RetryPolicy/RetryForever.php b/src/Recruiter/RetryPolicy/RetryForever.php
index 0eeb491e..57105fd1 100644
--- a/src/Recruiter/RetryPolicy/RetryForever.php
+++ b/src/Recruiter/RetryPolicy/RetryForever.php
@@ -1,19 +1,18 @@
$this->timeToWaitBeforeRetry->seconds()
+ 'seconds_to_wait_before_retry' => $this->timeToWaitBeforeRetry->seconds(),
];
}
public static function import(array $parameters): RetryPolicy
{
return new self(
- T\seconds($parameters['seconds_to_wait_before_retry'])
+ T\seconds($parameters['seconds_to_wait_before_retry']),
);
}
diff --git a/src/Recruiter/RetryPolicy/RetryManyTimes.php b/src/Recruiter/RetryPolicy/RetryManyTimes.php
index 31e99ba2..fa599ebe 100644
--- a/src/Recruiter/RetryPolicy/RetryManyTimes.php
+++ b/src/Recruiter/RetryPolicy/RetryManyTimes.php
@@ -1,21 +1,20 @@
$this->retryHowManyTimes,
- 'seconds_to_wait_before_retry' => $this->timeToWaitBeforeRetry->seconds()
+ 'seconds_to_wait_before_retry' => $this->timeToWaitBeforeRetry->seconds(),
];
}
@@ -51,7 +50,7 @@ public static function import(array $parameters): RetryPolicy
{
return new self(
$parameters['retry_how_many_times'],
- T\seconds($parameters['seconds_to_wait_before_retry'])
+ T\seconds($parameters['seconds_to_wait_before_retry']),
);
}
diff --git a/src/Recruiter/RetryPolicy/SelectByException.php b/src/Recruiter/RetryPolicy/SelectByException.php
index 0a2841db..98d814f4 100644
--- a/src/Recruiter/RetryPolicy/SelectByException.php
+++ b/src/Recruiter/RetryPolicy/SelectByException.php
@@ -3,14 +3,12 @@
namespace Recruiter\RetryPolicy;
use Exception;
-use InvalidArgumentException;
use Recruiter\Job;
use Recruiter\JobAfterFailure;
use Recruiter\RetryPolicy;
-use Throwable;
/**
- * Select retry policies based on the raised exception
+ * Select retry policies based on the raised exception.
*
* If a job fails with an exception it's possible to select a retry
* policy instance based on the class of the exception. The exception
@@ -41,9 +39,6 @@ public function __construct(array $exceptions)
$this->exceptions = $exceptions;
}
- /**
- * {@inheritDoc}
- */
public function schedule(JobAfterFailure $job)
{
$exception = $job->causeOfFailure();
@@ -54,56 +49,49 @@ public function schedule(JobAfterFailure $job)
}
}
- /**
- * {@inheritDoc}
- */
public function export(): array
{
return array_map(
- function(RetriableException $retriableException) {
+ function (RetriableException $retriableException) {
$retryPolicy = $retriableException->retryPolicy();
+
return [
'when' => $retriableException->exceptionClass(),
'then' => [
'class' => get_class($retryPolicy),
- 'parameters' => $retryPolicy->export()
- ]
+ 'parameters' => $retryPolicy->export(),
+ ],
];
},
- $this->exceptions
+ $this->exceptions,
);
}
- /**
- * {@inheritDoc}
- */
public static function import(array $parameters): RetryPolicy
{
return new self(
array_reduce(
$parameters,
- function($exceptions, $parameters) {
+ function ($exceptions, $parameters) {
$exceptionClass = $parameters['when'];
$retryPolicyClass = $parameters['then']['class'];
$retryPolicyParameters = $parameters['then']['parameters'];
$exceptions[] = new RetriableException($exceptionClass, $retryPolicyClass::import($retryPolicyParameters));
+
return $exceptions;
- }
- )
+ },
+ ),
);
}
- /**
- * {@inheritDoc}
- */
public function isLastRetry(Job $job): bool
{
// I cannot answer to that so... true only if everybody says true
return array_all(
$this->exceptions,
- function(RetriableException $retriableException) use ($job) {
+ function (RetriableException $retriableException) use ($job) {
return $retriableException->retryPolicy()->isLastRetry($job);
- }
+ },
);
}
@@ -111,8 +99,9 @@ private function isRetriable($exception): bool
{
try {
$this->retryPolicyFor($exception);
+
return true;
- } catch (Exception $e) {
+ } catch (\Exception $e) {
return false;
}
}
@@ -127,14 +116,10 @@ private function retryPolicyFor(?object $exception): RetryPolicy
return $retriableException->retryPolicy();
}
}
- if ($exception instanceof Throwable) {
- throw new Exception(
- 'Unable to find a RetryPolicy associated to exception: ' . get_class($exception), 0, $exception
- );
+ if ($exception instanceof \Throwable) {
+ throw new \Exception('Unable to find a RetryPolicy associated to exception: ' . get_class($exception), 0, $exception);
}
}
- throw new Exception(
- 'Unable to find a RetryPolicy associated to: ' . var_export($exception, true)
- );
+ throw new \Exception('Unable to find a RetryPolicy associated to: ' . var_export($exception, true));
}
}
diff --git a/src/Recruiter/RetryPolicy/SelectByExceptionBuilder.php b/src/Recruiter/RetryPolicy/SelectByExceptionBuilder.php
index b02f6602..6fa68c5c 100644
--- a/src/Recruiter/RetryPolicy/SelectByExceptionBuilder.php
+++ b/src/Recruiter/RetryPolicy/SelectByExceptionBuilder.php
@@ -1,12 +1,9 @@
currentException = $exceptionClass;
+
return $this;
}
@@ -39,6 +37,7 @@ public function then(RetryPolicy $retryPolicy): self
}
$this->exceptions[] = new RetriableException($this->currentException, $retryPolicy);
$this->currentException = null;
+
return $this;
}
@@ -50,6 +49,7 @@ public function build(): SelectByException
if (empty($this->exceptions)) {
throw new LogicException('No retry policies has been specified. Use `$builder->when($e)->then($r)`');
}
+
return new SelectByException($this->exceptions);
}
}
diff --git a/src/Recruiter/RetryPolicy/TimeTable.php b/src/Recruiter/RetryPolicy/TimeTable.php
index 0231b57c..b7d65d19 100644
--- a/src/Recruiter/RetryPolicy/TimeTable.php
+++ b/src/Recruiter/RetryPolicy/TimeTable.php
@@ -3,23 +3,19 @@
namespace Recruiter\RetryPolicy;
use Recruiter\Job;
+use Recruiter\JobAfterFailure;
use Recruiter\RetryPolicy;
use Recruiter\RetryPolicyBehaviour;
-use Recruiter\JobAfterFailure;
-
use Timeless as T;
-use Exception;
-
class TimeTable implements RetryPolicy
{
+ use RetryPolicyBehaviour;
/** @var array */
private $timeTable;
private $howManyRetries;
- use RetryPolicyBehaviour;
-
public function __construct(?array $timeTable)
{
if (is_null($timeTable)) {
@@ -47,6 +43,7 @@ public function isLastRetry(Job $job): bool
{
$timeSpents = array_keys($this->timeTable);
$timeSpent = end($timeSpents);
+
return !$this->hasBeenCreatedLessThan($job, $timeSpent);
}
@@ -63,14 +60,14 @@ public static function import(array $parameters): RetryPolicy
private function hasBeenCreatedLessThan($job, $relativeTime)
{
return $job->createdAt()->isAfter(
- T\Moment::fromTimestamp(strtotime($relativeTime, T\now()->seconds()))
+ T\Moment::fromTimestamp(strtotime($relativeTime, T\now()->seconds())),
);
}
private function rescheduleIn($job, $relativeTime)
{
$job->scheduleAt(
- T\Moment::fromTimestamp(strtotime($relativeTime, T\now()->seconds()))
+ T\Moment::fromTimestamp(strtotime($relativeTime, T\now()->seconds())),
);
}
@@ -82,23 +79,18 @@ private static function estimateHowManyRetriesIn($timeTable)
foreach ($timeTable as $timeWindow => $rescheduleTime) {
$timeWindowInSeconds = ($now - strtotime($timeWindow, $now)) - $timeWindowInSeconds;
if ($timeWindowInSeconds <= 0) {
- throw new Exception(
- "Time window `$timeWindow` is invalid, must be in the past"
- );
+ throw new \Exception("Time window `$timeWindow` is invalid, must be in the past");
}
$rescheduleTimeInSeconds = (strtotime($rescheduleTime, $now) - $now);
if ($rescheduleTimeInSeconds <= 0) {
- throw new Exception(
- "Reschedule time `$rescheduleTime` is invalid, must be in the future"
- );
+ throw new \Exception("Reschedule time `$rescheduleTime` is invalid, must be in the future");
}
if ($rescheduleTimeInSeconds > $timeWindowInSeconds) {
- throw new Exception(
- "Reschedule time `$rescheduleTime` is invalid, must be greater than the time window"
- );
+ throw new \Exception("Reschedule time `$rescheduleTime` is invalid, must be greater than the time window");
}
$howManyRetries += floor($timeWindowInSeconds / $rescheduleTimeInSeconds);
}
+
return $howManyRetries;
}
}
diff --git a/src/Recruiter/RetryPolicyBehaviour.php b/src/Recruiter/RetryPolicyBehaviour.php
index 9944ce04..d934bec6 100644
--- a/src/Recruiter/RetryPolicyBehaviour.php
+++ b/src/Recruiter/RetryPolicyBehaviour.php
@@ -2,9 +2,7 @@
namespace Recruiter;
-use Exception;
use Recruiter\RetryPolicy\RetriableExceptionFilter;
-use Recruiter\JobAfterFailure;
trait RetryPolicyBehaviour
{
@@ -27,7 +25,7 @@ public function retryOnlyWhenExceptionsAre($retriableExceptionTypes)
public function schedule(JobAfterFailure $job)
{
- throw new Exception('RetryPolicy::schedule(JobAfterFailure) need to be implemented');
+ throw new \Exception('RetryPolicy::schedule(JobAfterFailure) need to be implemented');
}
public function export(): array
diff --git a/src/Recruiter/RetryPolicyInJob.php b/src/Recruiter/RetryPolicyInJob.php
index 5f34814f..625645dc 100644
--- a/src/Recruiter/RetryPolicyInJob.php
+++ b/src/Recruiter/RetryPolicyInJob.php
@@ -2,26 +2,24 @@
namespace Recruiter;
-use Exception;
-use Recruiter\RetryPolicy;
-
class RetryPolicyInJob
{
public static function import($document)
{
if (!array_key_exists('retry_policy', $document)) {
- throw new Exception('Unable to import Job without data about RetryPolicy object');
+ throw new \Exception('Unable to import Job without data about RetryPolicy object');
}
$dataAboutRetryPolicyObject = $document['retry_policy'];
if (!array_key_exists('class', $dataAboutRetryPolicyObject)) {
- throw new Exception('Unable to import Job without a class');
+ throw new \Exception('Unable to import Job without a class');
}
if (!class_exists($dataAboutRetryPolicyObject['class'])) {
- throw new Exception('Unable to import Job with unknown RetryPolicy class');
+ throw new \Exception('Unable to import Job with unknown RetryPolicy class');
}
if (!method_exists($dataAboutRetryPolicyObject['class'], 'import')) {
- throw new Exception('Unable to import RetryPolicy without method import');
+ throw new \Exception('Unable to import RetryPolicy without method import');
}
+
return $dataAboutRetryPolicyObject['class']::import($dataAboutRetryPolicyObject['parameters']);
}
@@ -31,7 +29,7 @@ public static function export($retryPolicy)
'retry_policy' => [
'class' => get_class($retryPolicy),
'parameters' => $retryPolicy->export(),
- ]
+ ],
];
}
diff --git a/src/Recruiter/SchedulePolicy.php b/src/Recruiter/SchedulePolicy.php
index 21aeadd3..f10c701a 100644
--- a/src/Recruiter/SchedulePolicy.php
+++ b/src/Recruiter/SchedulePolicy.php
@@ -7,25 +7,19 @@
interface SchedulePolicy
{
/**
- * Returns the next time the job is to be executed
- *
- * @return Moment
+ * Returns the next time the job is to be executed.
*/
public function next(): Moment;
/**
- * Export schedule policy parameters
- *
- * @return array
+ * Export schedule policy parameters.
*/
public function export(): array;
/**
- * Import schedule policy parameters
+ * Import schedule policy parameters.
*
* @param array $parameters Previously exported parameters
- *
- * @return SchedulePolicy
*/
public static function import(array $parameters): SchedulePolicy;
}
diff --git a/src/Recruiter/SchedulePolicy/Cron.php b/src/Recruiter/SchedulePolicy/Cron.php
index 24afd0cc..8a3825fe 100644
--- a/src/Recruiter/SchedulePolicy/Cron.php
+++ b/src/Recruiter/SchedulePolicy/Cron.php
@@ -3,10 +3,7 @@
namespace Recruiter\SchedulePolicy;
use Cron\CronExpression;
-use DateInterval;
-use DateTime;
use Recruiter\SchedulePolicy;
-
use Timeless\Moment;
class Cron implements SchedulePolicy
@@ -14,7 +11,7 @@ class Cron implements SchedulePolicy
private $cronExpression;
private $now;
- public function __construct(string $cronExpression, ?DateTime $now = null)
+ public function __construct(string $cronExpression, ?\DateTime $now = null)
{
$this->cronExpression = $cronExpression;
$this->now = $now;
@@ -23,7 +20,7 @@ public function __construct(string $cronExpression, ?DateTime $now = null)
public function next(): Moment
{
return Moment::fromDateTime(
- CronExpression::factory($this->cronExpression)->getNextRunDate($this->now ?? 'now')
+ CronExpression::factory($this->cronExpression)->getNextRunDate($this->now ?? 'now'),
);
}
@@ -39,8 +36,8 @@ public static function import(array $parameters): SchedulePolicy
{
$now = null;
if (isset($parameters['now'])) {
- $now = DateTime::createFromFormat('U', $parameters['now']);
- $now = $now === false ? null : $now;
+ $now = \DateTime::createFromFormat('U', $parameters['now']);
+ $now = false === $now ? null : $now;
}
return new self($parameters['cron_expression'], $now);
diff --git a/src/Recruiter/SchedulePolicy/EveryMinutes.php b/src/Recruiter/SchedulePolicy/EveryMinutes.php
index 7245687e..908e5d55 100644
--- a/src/Recruiter/SchedulePolicy/EveryMinutes.php
+++ b/src/Recruiter/SchedulePolicy/EveryMinutes.php
@@ -2,9 +2,7 @@
namespace Recruiter\SchedulePolicy;
-use DateInterval;
use Recruiter\SchedulePolicy;
-
use Timeless\Moment;
class EveryMinutes implements SchedulePolicy
diff --git a/src/Recruiter/SchedulePolicyInJob.php b/src/Recruiter/SchedulePolicyInJob.php
index d1671ce6..3f376346 100644
--- a/src/Recruiter/SchedulePolicyInJob.php
+++ b/src/Recruiter/SchedulePolicyInJob.php
@@ -2,26 +2,24 @@
namespace Recruiter;
-use Exception;
-use Recruiter\SchedulePolicy;
-
class SchedulePolicyInJob
{
public static function import($document): SchedulePolicy
{
if (!array_key_exists('schedule_policy', $document)) {
- throw new Exception('Unable to import Job without data about SchedulePolicy object');
+ throw new \Exception('Unable to import Job without data about SchedulePolicy object');
}
$dataAboutSchedulePolicyObject = $document['schedule_policy'];
if (!array_key_exists('class', $dataAboutSchedulePolicyObject)) {
- throw new Exception('Unable to import Job without a SchedulePolicy class');
+ throw new \Exception('Unable to import Job without a SchedulePolicy class');
}
if (!class_exists($dataAboutSchedulePolicyObject['class'])) {
- throw new Exception('Unable to import Job with unknown SchedulePolicy class');
+ throw new \Exception('Unable to import Job with unknown SchedulePolicy class');
}
if (!method_exists($dataAboutSchedulePolicyObject['class'], 'import')) {
- throw new Exception('Unable to import SchedulePolicy without method import');
+ throw new \Exception('Unable to import SchedulePolicy without method import');
}
+
return $dataAboutSchedulePolicyObject['class']::import($dataAboutSchedulePolicyObject['parameters']);
}
@@ -31,7 +29,7 @@ public static function export($schedulePolicy)
'schedule_policy' => [
'class' => get_class($schedulePolicy),
'parameters' => $schedulePolicy->export(),
- ]
+ ],
];
}
diff --git a/src/Recruiter/Scheduler.php b/src/Recruiter/Scheduler.php
index 3c5a73e1..b6d8dd36 100644
--- a/src/Recruiter/Scheduler.php
+++ b/src/Recruiter/Scheduler.php
@@ -2,16 +2,9 @@
namespace Recruiter;
-use MongoDB\BSON\ObjectId;
-use Recruiter\Scheduler\Repository;
use Recruiter\Job\Repository as JobsRepository;
-use Recruiter\RetryPolicy;
-use RuntimeException;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Throwable;
+use Recruiter\Scheduler\Repository;
use Timeless as T;
-use Timeless\Interval;
-use Timeless\Moment;
class Scheduler
{
@@ -31,15 +24,14 @@ public static function around(Repeatable $repeatable, Repository $repository, Re
{
$retryPolicy = ($repeatable instanceof Retriable) ?
$repeatable->retryWithPolicy() :
- new RetryPolicy\DoNotDoItAgain()
- ;
+ new RetryPolicy\DoNotDoItAgain();
return new self(
self::initialize(),
$repeatable,
null,
$retryPolicy,
- $repository
+ $repository,
);
}
@@ -50,7 +42,7 @@ public static function import($document, Repository $repository)
RepeatableInJob::import($document['job']),
SchedulePolicyInJob::import($document),
RetryPolicyInJob::import($document['job']),
- $repository
+ $repository,
);
}
@@ -59,7 +51,7 @@ public function __construct(
Repeatable $repeatable,
?SchedulePolicy $schedulePolicy,
?RetryPolicy $retryPolicy,
- Repository $schedulers
+ Repository $schedulers,
) {
$this->status = $status;
$this->repeatable = $repeatable;
@@ -103,9 +95,9 @@ public function export()
[
'job' => array_merge(
WorkableInJob::export($this->repeatable, 'execute'),
- RetryPolicyInJob::export($this->retryPolicy)
+ RetryPolicyInJob::export($this->retryPolicy),
),
- ]
+ ],
);
}
@@ -128,8 +120,9 @@ private function aJobIsStillRunning(JobsRepository $jobs)
try {
$alreadyScheduledJob = $jobs->scheduled($this->status['last_scheduling']['job_id']);
+
return true;
- } catch (Throwable $e) {
+ } catch (\Throwable $e) {
return false;
}
}
@@ -137,7 +130,7 @@ private function aJobIsStillRunning(JobsRepository $jobs)
public function schedule(JobsRepository $jobs)
{
if (!$this->schedulePolicy) {
- throw new RuntimeException('You need to assign a `SchedulePolicy` (use `repeatWithPolicy` to inject it) in order to schedule a job');
+ throw new \RuntimeException('You need to assign a `SchedulePolicy` (use `repeatWithPolicy` to inject it) in order to schedule a job');
}
$nextScheduling = $this->schedulePolicy->next();
@@ -151,7 +144,7 @@ public function schedule(JobsRepository $jobs)
$this->status['last_scheduling']['scheduled_at'] = T\MongoDate::from($nextScheduling);
$this->status['last_scheduling']['job_id'] = null;
- $this->status['attempts'] += 1;
+ ++$this->status['attempts'];
$this->schedulers->save($this);
$jobToSchedule = (new JobToSchedule(Job::around($this->repeatable, $jobs)))
@@ -169,7 +162,7 @@ public function retryWithPolicy(RetryPolicy $retryPolicy, $retriableExceptionTyp
{
$this->retryPolicy = $this->filterForRetriableExceptions(
$retryPolicy,
- $retriableExceptionTypes
+ $retriableExceptionTypes,
);
return $this;
diff --git a/src/Recruiter/Scheduler/Repository.php b/src/Recruiter/Scheduler/Repository.php
index df95d856..61f8e3c0 100644
--- a/src/Recruiter/Scheduler/Repository.php
+++ b/src/Recruiter/Scheduler/Repository.php
@@ -1,14 +1,9 @@
map(
$this->schedulers->find([], [
'sort' => ['scheduled_at' => -1],
- ])
+ ]),
);
}
@@ -34,7 +29,7 @@ public function save(Scheduler $scheduler)
$this->schedulers->replaceOne(
['_id' => $document['_id']],
$document,
- ['upsert' => true]
+ ['upsert' => true],
);
}
@@ -55,7 +50,7 @@ public function create(Scheduler $scheduler)
$this->schedulers->updateOne(
['urn' => $scheduler->urn()],
- ['$set' => $document]
+ ['$set' => $document],
);
}
}
diff --git a/src/Recruiter/SynchronousExecutionReport.php b/src/Recruiter/SynchronousExecutionReport.php
index 68132ed6..2775aa5e 100644
--- a/src/Recruiter/SynchronousExecutionReport.php
+++ b/src/Recruiter/SynchronousExecutionReport.php
@@ -1,10 +1,11 @@
data = $data;
}
-
/**
- *. @params array $data : key value array where key are the id of the job and value is the JobExecution
+ *. @params array $data : key value array where key are the id of the job and value is the JobExecution.
*/
public static function fromArray(array $data): SynchronousExecutionReport
{
diff --git a/src/Recruiter/Taggable.php b/src/Recruiter/Taggable.php
index 6ab0d0e0..0e9354e3 100644
--- a/src/Recruiter/Taggable.php
+++ b/src/Recruiter/Taggable.php
@@ -5,7 +5,7 @@
interface Taggable
{
/**
- * A Job can decide its own tags. Tags are useful to correlate jobs
+ * A Job can decide its own tags. Tags are useful to correlate jobs.
*
* @return array Strings to be used to tag the job
*/
diff --git a/src/Recruiter/WaitStrategy.php b/src/Recruiter/WaitStrategy.php
index 4e41d029..0b71e42f 100644
--- a/src/Recruiter/WaitStrategy.php
+++ b/src/Recruiter/WaitStrategy.php
@@ -22,6 +22,7 @@ public function __construct(Interval $timeToWaitAtLeast, Interval $timeToWaitAtM
public function reset()
{
$this->timeToWait = $this->timeToWaitAtLeast;
+
return $this;
}
@@ -29,8 +30,9 @@ public function goForward()
{
$this->timeToWait = max(
$this->timeToWait / 2,
- $this->timeToWaitAtLeast
+ $this->timeToWaitAtLeast,
);
+
return $this;
}
@@ -38,14 +40,16 @@ public function backOff()
{
$this->timeToWait = min(
$this->timeToWait * 2,
- $this->timeToWaitAtMost
+ $this->timeToWaitAtMost,
);
+
return $this;
}
public function wait()
{
call_user_func($this->howToWait, $this->timeToWait * 1000);
+
return $this;
}
diff --git a/src/Recruiter/Workable.php b/src/Recruiter/Workable.php
index 4a9733df..937317a1 100644
--- a/src/Recruiter/Workable.php
+++ b/src/Recruiter/Workable.php
@@ -5,19 +5,17 @@
interface Workable
{
/**
- * Turn this `Recruiter\Workable` instance into a `Recruiter\Job` instance
+ * Turn this `Recruiter\Workable` instance into a `Recruiter\Job` instance.
*/
public function asJobOf(Recruiter $recruiter): JobToSchedule;
/**
- * Export parameters that need to be persisted
- *
- * @return array
+ * Export parameters that need to be persisted.
*/
public function export(): array;
/**
- * Import an array of parameters as a Workable instance
+ * Import an array of parameters as a Workable instance.
*
* @param array $parameters Previously exported parameters
*/
diff --git a/src/Recruiter/Workable/AlwaysFail.php b/src/Recruiter/Workable/AlwaysFail.php
index 485e967e..3a90f1fa 100644
--- a/src/Recruiter/Workable/AlwaysFail.php
+++ b/src/Recruiter/Workable/AlwaysFail.php
@@ -1,7 +1,7 @@
parameters['howManyItems']);
}
}
-
diff --git a/src/Recruiter/Workable/FactoryMethodCommand.php b/src/Recruiter/Workable/FactoryMethodCommand.php
index 8a354534..deac6c23 100644
--- a/src/Recruiter/Workable/FactoryMethodCommand.php
+++ b/src/Recruiter/Workable/FactoryMethodCommand.php
@@ -1,17 +1,18 @@
steps[] = $step;
+
return $this;
}
diff --git a/src/Recruiter/Workable/FailsInConstructor.php b/src/Recruiter/Workable/FailsInConstructor.php
index 9523f5b0..2d70eb0e 100644
--- a/src/Recruiter/Workable/FailsInConstructor.php
+++ b/src/Recruiter/Workable/FailsInConstructor.php
@@ -1,7 +1,7 @@
usToSleep + (rand(intval(-$this->usOfDelta), $this->usOfDelta)));
+ usleep($this->usToSleep + rand(intval(-$this->usOfDelta), $this->usOfDelta));
}
public function export(): array
@@ -41,7 +40,7 @@ public static function import(array $parameters): static
{
return new self(
$parameters['us_to_sleep'],
- $parameters['us_of_delta']
+ $parameters['us_of_delta'],
);
}
}
diff --git a/src/Recruiter/Workable/RecoverRepeatableFromException.php b/src/Recruiter/Workable/RecoverRepeatableFromException.php
index 4fcce94c..4521f879 100644
--- a/src/Recruiter/Workable/RecoverRepeatableFromException.php
+++ b/src/Recruiter/Workable/RecoverRepeatableFromException.php
@@ -1,7 +1,7 @@
recoverForClass . PHP_EOL .
- 'Original exception: ' . get_class($this->recoverForException) . PHP_EOL .
- $this->recoverForException->getMessage() . PHP_EOL .
- $this->recoverForException->getTraceAsString() . PHP_EOL
- );
+ throw new \Exception('This job failed while instantiating a workable of class: ' . $this->recoverForClass . PHP_EOL . 'Original exception: ' . get_class($this->recoverForException) . PHP_EOL . $this->recoverForException->getMessage() . PHP_EOL . $this->recoverForException->getTraceAsString() . PHP_EOL);
}
public function getClass()
@@ -38,6 +33,7 @@ public function urn(): string
{
$recoverForInstance = new $this->recoverForClass($this->parameters);
assert($recoverForInstance instanceof Repeatable);
+
return $recoverForInstance->urn();
}
@@ -45,6 +41,7 @@ public function unique(): bool
{
$recoverForInstance = new $this->recoverForClass($this->parameters);
assert($recoverForInstance instanceof Repeatable);
+
return $recoverForInstance->unique();
}
}
diff --git a/src/Recruiter/Workable/RecoverWorkableFromException.php b/src/Recruiter/Workable/RecoverWorkableFromException.php
index 53e2fc67..6993f755 100644
--- a/src/Recruiter/Workable/RecoverWorkableFromException.php
+++ b/src/Recruiter/Workable/RecoverWorkableFromException.php
@@ -1,7 +1,7 @@
recoverForClass . PHP_EOL .
- 'Original exception: ' . get_class($this->recoverForException) . PHP_EOL .
- $this->recoverForException->getMessage() . PHP_EOL .
- $this->recoverForException->getTraceAsString() . PHP_EOL
- );
+ throw new \Exception('This job failed while instantiating a workable of class: ' . $this->recoverForClass . PHP_EOL . 'Original exception: ' . get_class($this->recoverForException) . PHP_EOL . $this->recoverForException->getMessage() . PHP_EOL . $this->recoverForException->getTraceAsString() . PHP_EOL);
}
public function getClass()
diff --git a/src/Recruiter/Workable/SampleRepeatableCommand.php b/src/Recruiter/Workable/SampleRepeatableCommand.php
index 92a57b5c..62faad5c 100644
--- a/src/Recruiter/Workable/SampleRepeatableCommand.php
+++ b/src/Recruiter/Workable/SampleRepeatableCommand.php
@@ -3,15 +3,14 @@
namespace Recruiter\Workable;
use Recruiter\Repeatable;
-use Recruiter\SchedulePolicy\EveryMinutes;
-use Recruiter\SchedulePolicy;
+use Recruiter\RepeatableBehaviour;
use Recruiter\Workable;
use Recruiter\WorkableBehaviour;
-use Recruiter\RepeatableBehaviour;
class SampleRepeatableCommand implements Workable, Repeatable
{
- use WorkableBehaviour, RepeatableBehaviour;
+ use WorkableBehaviour;
+ use RepeatableBehaviour;
public function execute()
{
diff --git a/src/Recruiter/Workable/ShellCommand.php b/src/Recruiter/Workable/ShellCommand.php
index ee8c3543..2e763704 100644
--- a/src/Recruiter/Workable/ShellCommand.php
+++ b/src/Recruiter/Workable/ShellCommand.php
@@ -4,7 +4,6 @@
use Recruiter\Workable;
use Recruiter\WorkableBehaviour;
-use RuntimeException;
class ShellCommand implements Workable
{
@@ -26,9 +25,10 @@ public function execute()
{
exec($this->commandLine, $output, $returnCode);
$output = implode(PHP_EOL, $output);
- if ($returnCode != 0) {
- throw new RuntimeException("Command execution failed (return code $returnCode). Output: " . $output);
+ if (0 != $returnCode) {
+ throw new \RuntimeException("Command execution failed (return code $returnCode). Output: " . $output);
}
+
return $output;
}
diff --git a/src/Recruiter/Workable/ThrowsFatalError.php b/src/Recruiter/Workable/ThrowsFatalError.php
index f8a16eaa..a80a0211 100644
--- a/src/Recruiter/Workable/ThrowsFatalError.php
+++ b/src/Recruiter/Workable/ThrowsFatalError.php
@@ -1,4 +1,5 @@
self::classNameOf($workable),
'parameters' => $workable->export(),
'method' => $methodToCall,
- ]
+ ],
];
}
@@ -60,6 +59,7 @@ private static function classNameOf($workable)
if (method_exists($workable, 'getClass')) {
$workableClassName = $workable->getClass();
}
+
return $workableClassName;
}
}
diff --git a/src/Recruiter/Worker.php b/src/Recruiter/Worker.php
index 8ea0c97c..e9885622 100644
--- a/src/Recruiter/Worker.php
+++ b/src/Recruiter/Worker.php
@@ -2,8 +2,6 @@
namespace Recruiter;
-use DateInterval;
-use DateTimeImmutable;
use MongoDB\BSON\ObjectId;
use MongoDB\Collection as MongoCollection;
use Recruiter\Infrastructure\Memory\MemoryLimit;
@@ -11,7 +9,6 @@
use Recruiter\Worker\Repository;
use Timeless as T;
use Timeless\Interval;
-use Timeless\Moment;
class Worker
{
@@ -23,10 +20,11 @@ class Worker
public static function workFor(
Recruiter $recruiter,
Repository $repository,
- MemoryLimit $memoryLimit
+ MemoryLimit $memoryLimit,
) {
$worker = new self(self::initialize(), $recruiter, $repository, $memoryLimit);
$worker->save();
+
return $worker;
}
@@ -34,7 +32,7 @@ public function __construct(
$status,
Recruiter $recruiter,
Repository $repository,
- MemoryLimit $memoryLimit
+ MemoryLimit $memoryLimit,
) {
$this->status = $status;
$this->recruiter = $recruiter;
@@ -58,12 +56,14 @@ public function work()
if ($this->hasBeenAssignedToDoSomething()) {
$this->workOn(
$job = $this->recruiter->scheduledJob(
- $this->status['assigned_to'][(string)$this->status['_id']]
- )
+ $this->status['assigned_to'][(string) $this->status['_id']],
+ ),
);
+
return (string) $job->id();
} else {
$this->stillHere();
+
return false;
}
}
@@ -132,7 +132,7 @@ private function afterExecutionOf($job)
$this->id(),
$job->id(),
get_class($e),
- $e->getMessage()
+ $e->getMessage(),
);
$this->retireAfterMemoryLimitIsExceeded();
@@ -154,7 +154,6 @@ private function retireAfterMemoryLimitIsExceeded()
$this->repository->retireWorkerWithId($this->id());
}
-
private function hasBeenAssignedToDoSomething()
{
if (is_null($this->status)) {
@@ -164,6 +163,7 @@ private function hasBeenAssignedToDoSomething()
// thing to do seems like terminate the process
exit(1);
}
+
return array_key_exists('assigned_to', $this->status);
}
@@ -192,13 +192,13 @@ private static function initialize()
'last_seen_at' => T\MongoDate::now(),
'created_at' => T\MongoDate::now(),
'working' => false,
- 'pid' => getmypid()
+ 'pid' => getmypid(),
];
}
public static function canWorkOnAnyJobs($worksOn)
{
- return $worksOn === '*';
+ return '*' === $worksOn;
}
public static function pickAvailableWorkers(MongoCollection $collection, $workersPerUnit)
@@ -210,7 +210,7 @@ public static function pickAvailableWorkers(MongoCollection $collection, $worker
$workers,
function ($worker) {
return $worker['work_on'];
- }
+ },
);
foreach ($unitsOfWorkers as $workOn => $workersInUnit) {
$workersInUnit = array_column($workersInUnit, '_id');
@@ -218,6 +218,7 @@ function ($worker) {
$result[] = [$workOn, $workersInUnit];
}
}
+
return $result;
}
@@ -225,9 +226,9 @@ public static function tryToAssignJobsToWorkers(MongoCollection $collection, $jo
{
$assignment = array_combine(
array_map(function ($id) {
- return (string)$id;
+ return (string) $id;
}, $workers),
- $jobs
+ $jobs,
);
$result = $collection->updateMany(
@@ -235,8 +236,8 @@ public static function tryToAssignJobsToWorkers(MongoCollection $collection, $jo
$update = ['$set' => [
'available' => false,
'assigned_to' => $assignment,
- 'assigned_since' => T\MongoDate::now()
- ]]
+ 'assigned_since' => T\MongoDate::now(),
+ ]],
);
return [$assignment, $result->getModifiedCount()];
@@ -258,7 +259,7 @@ public static function assignedJobs(MongoCollection $collection)
return array_values(array_unique($jobs));
}
- public static function retireDeadWorkers(Repository $roster, DateTimeImmutable $now, Interval $consideredDeadAfter)
+ public static function retireDeadWorkers(Repository $roster, \DateTimeImmutable $now, Interval $consideredDeadAfter)
{
$consideredDeadAt = $now->sub($consideredDeadAfter->toDateInterval());
$deadWorkers = $roster->deadWorkers($consideredDeadAt);
@@ -266,8 +267,8 @@ public static function retireDeadWorkers(Repository $roster, DateTimeImmutable $
foreach ($deadWorkers as $deadWorker) {
$roster->retireWorkerWithId($deadWorker['_id']);
if (array_key_exists('assigned_to', $deadWorker)) {
- if (array_key_exists((string)$deadWorker['_id'], $deadWorker['assigned_to'])) {
- $jobsToReassign[] = $deadWorker['assigned_to'][(string)$deadWorker['_id']];
+ if (array_key_exists((string) $deadWorker['_id'], $deadWorker['assigned_to'])) {
+ $jobsToReassign[] = $deadWorker['assigned_to'][(string) $deadWorker['_id']];
}
}
}
diff --git a/src/Recruiter/Worker/Process.php b/src/Recruiter/Worker/Process.php
index 064f52ee..2dd02853 100644
--- a/src/Recruiter/Worker/Process.php
+++ b/src/Recruiter/Worker/Process.php
@@ -3,7 +3,6 @@
namespace Recruiter\Worker;
use Sink\BlackHole;
-use Recruiter\Worker\Repository;
class Process
{
@@ -31,6 +30,7 @@ public function ifDead()
if ($this->isAlive()) {
return new BlackHole();
}
+
return $this;
}
diff --git a/src/Recruiter/Worker/Repository.php b/src/Recruiter/Worker/Repository.php
index b54ad992..1e04a7d4 100644
--- a/src/Recruiter/Worker/Repository.php
+++ b/src/Recruiter/Worker/Repository.php
@@ -5,7 +5,6 @@
use MongoDB;
use MongoDB\BSON\UTCDateTime as MongoUTCDateTime;
use Recruiter\Recruiter;
-use Recruiter\Worker;
class Repository
{
@@ -24,7 +23,7 @@ public function save($worker)
$result = $this->roster->replaceOne(
['_id' => $document['_id']],
$document,
- ['upsert' => true]
+ ['upsert' => true],
);
}
@@ -32,14 +31,14 @@ public function atomicUpdate($worker, array $changeSet)
{
$this->roster->updateOne(
['_id' => $worker->id()],
- ['$set' => $changeSet]
+ ['$set' => $changeSet],
);
}
public function refresh($worker)
{
$worker->updateWith(
- $this->roster->findOne(['_id' => $worker->id()])
+ $this->roster->findOne(['_id' => $worker->id()]),
);
}
@@ -47,9 +46,9 @@ public function deadWorkers($consideredDeadAt)
{
return $this->roster->find(
['last_seen_at' => [
- '$lt' => new MongoUTCDateTime($consideredDeadAt->format('U') * 1000)]
+ '$lt' => new MongoUTCDateTime($consideredDeadAt->format('U') * 1000)],
],
- ['projection' => ['_id' => true, 'assigned_to' => true]]
+ ['projection' => ['_id' => true, 'assigned_to' => true]],
);
}
diff --git a/src/Recruiter/WorkerDiedInTheLineOfDutyException.php b/src/Recruiter/WorkerDiedInTheLineOfDutyException.php
index 7a3d83e0..6543f13b 100644
--- a/src/Recruiter/WorkerDiedInTheLineOfDutyException.php
+++ b/src/Recruiter/WorkerDiedInTheLineOfDutyException.php
@@ -1,8 +1,7 @@
seconds()}S");
+ return new \DateInterval("PT{$this->seconds()}S");
}
public static function parse($string)
@@ -163,7 +162,7 @@ public static function parse($string)
'years' => 'years', 'year' => 'years', 'y' => 'years',
];
$units = implode('|', array_keys($tokenToFunction));
- if (preg_match("/^[^\d]*(?P\d+)\s*(?P{$units})(?:\W.*|$)/", $string, $matches)) {
+ if (preg_match("/^[^\\d]*(?P\\d+)\\s*(?P{$units})(?:\\W.*|$)/", $string, $matches)) {
$callable = 'Timeless\\' . $tokenToFunction[$matches['unit']];
if (is_callable($callable)) {
return call_user_func($callable, $matches['quantity']);
@@ -182,10 +181,11 @@ public static function parse($string)
throw new InvalidIntervalFormat('You need to use strings');
}
- public static function fromDateInterval(DateInterval $interval): self
+ public static function fromDateInterval(\DateInterval $interval): self
{
- $startTime = new DateTimeImmutable();
+ $startTime = new \DateTimeImmutable();
$endTime = $startTime->add($interval);
+
return new self(($endTime->getTimestamp() - $startTime->getTimestamp()) * 1000);
}
}
diff --git a/src/Timeless/InvalidIntervalFormat.php b/src/Timeless/InvalidIntervalFormat.php
index 55ca83b4..01175de2 100644
--- a/src/Timeless/InvalidIntervalFormat.php
+++ b/src/Timeless/InvalidIntervalFormat.php
@@ -2,8 +2,6 @@
namespace Timeless;
-use Exception;
-
-class InvalidIntervalFormat extends Exception
+class InvalidIntervalFormat extends \Exception
{
}
diff --git a/src/Timeless/Moment.php b/src/Timeless/Moment.php
index fd6c96cf..4e394126 100644
--- a/src/Timeless/Moment.php
+++ b/src/Timeless/Moment.php
@@ -2,9 +2,6 @@
namespace Timeless;
-use DateTime;
-use DateTimeZone;
-
readonly class Moment
{
public static function fromTimestamp(int $ts): self
@@ -12,7 +9,7 @@ public static function fromTimestamp(int $ts): self
return new self($ts * 1000);
}
- public static function fromDateTime(DateTime $dateTime): self
+ public static function fromDateTime(\DateTime $dateTime): self
{
return self::fromTimestamp($dateTime->getTimestamp());
}
@@ -68,11 +65,11 @@ public function toSecondPrecision(): Moment
public function format(): string
{
- return new DateTime('@' . $this->s(), new DateTimeZone('UTC'))->format(DateTime::RFC3339);
+ return new \DateTime('@' . $this->s(), new \DateTimeZone('UTC'))->format(\DateTime::RFC3339);
}
- public function toDateTime(): DateTime
+ public function toDateTime(): \DateTime
{
- return new DateTime('@' . $this->s(), new DateTimeZone('UTC'));
+ return new \DateTime('@' . $this->s(), new \DateTimeZone('UTC'));
}
}
diff --git a/src/Timeless/MongoDate.php b/src/Timeless/MongoDate.php
index 255ccdc2..d61714de 100644
--- a/src/Timeless/MongoDate.php
+++ b/src/Timeless/MongoDate.php
@@ -1,4 +1,5 @@
Date: Sun, 3 Aug 2025 12:26:02 +0200
Subject: [PATCH 25/59] Use a dist file instead
---
.gitignore | 1 +
phpunit.xml => phpunit.dist.xml | 0
2 files changed, 1 insertion(+)
rename phpunit.xml => phpunit.dist.xml (100%)
diff --git a/.gitignore b/.gitignore
index d1b4fe30..01beab6a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.*.cache
+phpunit.xml
composer.phar
composer.lock
vendor/
diff --git a/phpunit.xml b/phpunit.dist.xml
similarity index 100%
rename from phpunit.xml
rename to phpunit.dist.xml
From db6d5fa1ee8270b56607f7f4eac42c89b7bc6935 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 12:33:21 +0200
Subject: [PATCH 26/59] Remove setMethods
---
spec/Recruiter/JobCallCustomMethodOnWorkableTest.php | 2 +-
spec/Recruiter/RetryPolicy/TimeTableTest.php | 4 ++--
spec/Recruiter/WorkerProcessTest.php | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
index a71b8d94..0aecfe08 100644
--- a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
+++ b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
@@ -16,7 +16,7 @@ protected function setUp(): void
{
$this->workable = $this
->getMockBuilder(Workable::class)
- ->setMethods(['export', 'import', 'asJobOf', 'send'])
+ ->onlyMethods(['export', 'import', 'asJobOf', 'send'])
->getMock()
;
diff --git a/spec/Recruiter/RetryPolicy/TimeTableTest.php b/spec/Recruiter/RetryPolicy/TimeTableTest.php
index 2ce8ea2e..5e943fa0 100644
--- a/spec/Recruiter/RetryPolicy/TimeTableTest.php
+++ b/spec/Recruiter/RetryPolicy/TimeTableTest.php
@@ -113,7 +113,7 @@ private function givenJobThat(T\Moment $wasCreatedAt)
{
$job = $this->getMockBuilder('Recruiter\JobAfterFailure')
->disableOriginalConstructor()
- ->setMethods(['createdAt', 'scheduleAt'])
+ ->onlyMethods(['createdAt', 'scheduleAt'])
->getMock()
;
$job->expects($this->any())
@@ -129,7 +129,7 @@ private function jobThatWasCreated($relativeTime)
$wasCreatedAt = T\Moment::fromTimestamp(strtotime($relativeTime));
$job = $this->getMockBuilder('Recruiter\JobAfterFailure')
->disableOriginalConstructor()
- ->setMethods(['createdAt', 'scheduleAt'])
+ ->onlyMethods(['createdAt', 'scheduleAt'])
->getMock()
;
$job->expects($this->any())
diff --git a/spec/Recruiter/WorkerProcessTest.php b/spec/Recruiter/WorkerProcessTest.php
index f3d7bfdd..2f241a00 100644
--- a/spec/Recruiter/WorkerProcessTest.php
+++ b/spec/Recruiter/WorkerProcessTest.php
@@ -72,7 +72,7 @@ private function givenWorkerProcessDead()
private function givenWorkerProcess($alive)
{
$process = $this->getMockBuilder('Recruiter\Worker\Process')
- ->setMethods(['isAlive'])
+ ->onlyMethods(['isAlive'])
->setConstructorArgs([$this->pid])
->getMock()
;
From 333da6942cd303792a24fb47e36d8d5d2ea40015 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 13:00:02 +0200
Subject: [PATCH 27/59] Use ::class everywhere
---
spec/Recruiter/CleanerTest.php | 3 ++-
spec/Recruiter/Job/RepositoryTest.php | 6 ++++--
spec/Recruiter/JobCallCustomMethodOnWorkableTest.php | 3 ++-
spec/Recruiter/JobTest.php | 3 ++-
spec/Recruiter/JobToScheduleTest.php | 5 +++--
spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php | 3 ++-
.../RetryPolicy/RetriableExceptionFilterTest.php | 3 ++-
spec/Recruiter/RetryPolicy/SelectByExceptionTest.php | 3 ++-
spec/Recruiter/RetryPolicy/TimeTableTest.php | 10 ++++++----
spec/Recruiter/WorkerProcessTest.php | 2 +-
10 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/spec/Recruiter/CleanerTest.php b/spec/Recruiter/CleanerTest.php
index d1d99c4c..0c8edb7f 100644
--- a/spec/Recruiter/CleanerTest.php
+++ b/spec/Recruiter/CleanerTest.php
@@ -4,6 +4,7 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+use Recruiter\Job\Repository;
use Timeless as T;
use Timeless\Interval;
use Timeless\Moment;
@@ -22,7 +23,7 @@ protected function setUp(): void
$this->now = $this->clock->now();
$this->jobRepository = $this
- ->getMockBuilder('Recruiter\Job\Repository')
+ ->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock()
;
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 7b6aacb3..62ba7f0a 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -10,7 +10,9 @@
use Recruiter\Factory;
use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
use Recruiter\Job;
+use Recruiter\JobExecution;
use Recruiter\JobToSchedule;
+use Recruiter\Workable;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Timeless as T;
use Timeless\Interval;
@@ -440,7 +442,7 @@ private function aJobToSchedule($job = null)
private function workableMock()
{
return $this
- ->getMockBuilder('Recruiter\Workable')
+ ->getMockBuilder(Workable::class)
->getMock()
;
}
@@ -460,7 +462,7 @@ private function workableMockWithCustomParameters($parameters)
private function jobExecutionMock($executionParameters)
{
$jobExecutionMock = $this
- ->getMockBuilder('Recruiter\JobExecution')
+ ->getMockBuilder(JobExecution::class)
->getMock()
;
$jobExecutionMock->expects($this->once())
diff --git a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
index 0aecfe08..b3a9d522 100644
--- a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
+++ b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
@@ -5,6 +5,7 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Recruiter\Job\Repository;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class JobCallCustomMethodOnWorkableTest extends TestCase
{
@@ -33,7 +34,7 @@ public function testConfigureMethodToCallOnWorkable()
{
$this->workable->expects($this->once())->method('send');
$this->job->methodToCallOnWorkable('send');
- $this->job->execute($this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'));
+ $this->job->execute($this->createMock(EventDispatcherInterface::class));
}
public function testRaiseExceptionWhenConfigureMethodToCallOnWorkableThatDoNotExists()
diff --git a/spec/Recruiter/JobTest.php b/spec/Recruiter/JobTest.php
index b419fc29..261f7575 100644
--- a/spec/Recruiter/JobTest.php
+++ b/spec/Recruiter/JobTest.php
@@ -7,6 +7,7 @@
use Recruiter\Infrastructure\Memory\MemoryLimit;
use Recruiter\Job\Repository;
use Recruiter\Workable\AlwaysFail;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class JobTest extends TestCase
{
@@ -41,7 +42,7 @@ public function testRetryStatisticsOnSubsequentExecutions()
{
$job = Job::around(new AlwaysFail(), $this->repository);
// maybe make the argument optional
- $job->execute($this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'));
+ $job->execute($this->createMock(EventDispatcherInterface::class));
$job = Job::import($job->export(), $this->repository);
$retryStatistics = $job->retryStatistics();
$this->assertEquals(1, $retryStatistics['retry_number']);
diff --git a/spec/Recruiter/JobToScheduleTest.php b/spec/Recruiter/JobToScheduleTest.php
index b81c8afb..27b9496a 100644
--- a/spec/Recruiter/JobToScheduleTest.php
+++ b/spec/Recruiter/JobToScheduleTest.php
@@ -4,6 +4,7 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Timeless as T;
class JobToScheduleTest extends TestCase
@@ -123,7 +124,7 @@ public function testShouldExecuteJobWhenNotScheduled()
(new JobToSchedule($this->job))
->execute(
- $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'),
+ $this->createMock(EventDispatcherInterface::class),
)
;
}
@@ -153,7 +154,7 @@ public function testReturnsJobId()
'42',
(new JobToSchedule($this->job))
->execute(
- $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'),
+ $this->createMock(EventDispatcherInterface::class),
),
);
}
diff --git a/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php b/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
index 102c100a..5c6e9e52 100644
--- a/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
+++ b/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
@@ -3,6 +3,7 @@
namespace Recruiter\RetryPolicy;
use PHPUnit\Framework\TestCase;
+use Recruiter\JobAfterFailure;
use Timeless as T;
class ExponentialBackoffTest extends TestCase
@@ -53,7 +54,7 @@ public function testCanBeCreatedByTargetingAMaximumInterval()
private function jobExecutedFor($times)
{
- $job = $this->getMockBuilder('Recruiter\JobAfterFailure')->disableOriginalConstructor()->getMock();
+ $job = $this->getMockBuilder(JobAfterFailure::class)->disableOriginalConstructor()->getMock();
$job->expects($this->any())
->method('numberOfAttempts')
->will($this->returnValue($times))
diff --git a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
index 13ccdfd7..09d8ae91 100644
--- a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
+++ b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
@@ -4,6 +4,7 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+use Recruiter\JobAfterFailure;
use Recruiter\RetryPolicy;
class RetriableExceptionFilterTest extends TestCase
@@ -130,7 +131,7 @@ public function testRetriableExceptionsThatAreNotExceptions()
private function jobFailedWithException($exception)
{
$jobAfterFailure = $this
- ->getMockBuilder('Recruiter\JobAfterFailure')
+ ->getMockBuilder(JobAfterFailure::class)
->disableOriginalConstructor()
->getMock()
;
diff --git a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
index 91f62db4..45c5904e 100644
--- a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
+++ b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
@@ -3,6 +3,7 @@
namespace Recruiter\RetryPolicy;
use PHPUnit\Framework\TestCase;
+use Recruiter\JobAfterFailure;
use Recruiter\RetryPolicy;
use Timeless as T;
@@ -66,7 +67,7 @@ public function testDefaultDoNotSchedule()
private function jobFailedWith(\Exception $exception)
{
- $job = $this->getMockBuilder('Recruiter\JobAfterFailure')->disableOriginalConstructor()->getMock();
+ $job = $this->getMockBuilder(JobAfterFailure::class)->disableOriginalConstructor()->getMock();
$job->expects($this->any())
->method('causeOfFailure')
->will($this->returnValue($exception))
diff --git a/spec/Recruiter/RetryPolicy/TimeTableTest.php b/spec/Recruiter/RetryPolicy/TimeTableTest.php
index 5e943fa0..d5361aaa 100644
--- a/spec/Recruiter/RetryPolicy/TimeTableTest.php
+++ b/spec/Recruiter/RetryPolicy/TimeTableTest.php
@@ -3,6 +3,8 @@
namespace Recruiter\RetryPolicy;
use PHPUnit\Framework\TestCase;
+use Recruiter\Job;
+use Recruiter\JobAfterFailure;
use Timeless as T;
class TimeTableTest extends TestCase
@@ -63,7 +65,7 @@ public function testShouldNotBeRescheduledWhenWasCreatedMoreThan24HoursAgo()
public function testIsLastRetryReturnTrueIfJobWasCreatedMoreThanLastTimeSpen()
{
- $job = $this->createMock('Recruiter\Job');
+ $job = $this->createMock(Job::class);
$job->expects($this->any())
->method('createdAt')
->will($this->returnValue(T\hours(3)->ago()))
@@ -78,7 +80,7 @@ public function testIsLastRetryReturnTrueIfJobWasCreatedMoreThanLastTimeSpen()
public function testIsLastRetryReturnFalseIfJobWasCreatedLessThanLastTimeSpen()
{
- $job = $this->createMock('Recruiter\Job');
+ $job = $this->createMock(Job::class);
$job->expects($this->any())
->method('createdAt')
->will($this->returnValue(T\hours(3)->ago()))
@@ -111,7 +113,7 @@ public function testInvalidTimeTableBecauseRescheduleTimeIsGreaterThanTimeWindow
private function givenJobThat(T\Moment $wasCreatedAt)
{
- $job = $this->getMockBuilder('Recruiter\JobAfterFailure')
+ $job = $this->getMockBuilder(JobAfterFailure::class)
->disableOriginalConstructor()
->onlyMethods(['createdAt', 'scheduleAt'])
->getMock()
@@ -127,7 +129,7 @@ private function givenJobThat(T\Moment $wasCreatedAt)
private function jobThatWasCreated($relativeTime)
{
$wasCreatedAt = T\Moment::fromTimestamp(strtotime($relativeTime));
- $job = $this->getMockBuilder('Recruiter\JobAfterFailure')
+ $job = $this->getMockBuilder(JobAfterFailure::class)
->disableOriginalConstructor()
->onlyMethods(['createdAt', 'scheduleAt'])
->getMock()
diff --git a/spec/Recruiter/WorkerProcessTest.php b/spec/Recruiter/WorkerProcessTest.php
index 2f241a00..bcd50437 100644
--- a/spec/Recruiter/WorkerProcessTest.php
+++ b/spec/Recruiter/WorkerProcessTest.php
@@ -71,7 +71,7 @@ private function givenWorkerProcessDead()
private function givenWorkerProcess($alive)
{
- $process = $this->getMockBuilder('Recruiter\Worker\Process')
+ $process = $this->getMockBuilder(Process::class)
->onlyMethods(['isAlive'])
->setConstructorArgs([$this->pid])
->getMock()
From 75e42ba364c4406c282f49b04667306533624ac1 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 13:00:10 +0200
Subject: [PATCH 28/59] Fix Coding Standards
---
spec/Recruiter/Job/RepositoryTest.php | 5 +++--
spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php | 3 ++-
spec/Recruiter/RetryPolicy/TimeTableTest.php | 3 ++-
3 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 62ba7f0a..e6dc1a25 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -490,7 +490,7 @@ private function jobMockWithAttemptsAndCustomParameters(
'ended_at' => T\MongoDate::from($endedAt),
],
'retry_policy' => [
- 'class' => 'Recruiter\\RetryPolicy\\DoNotDoItAgain',
+ 'class' => 'Recruiter\RetryPolicy\DoNotDoItAgain',
'parameters' => [],
],
];
@@ -507,7 +507,8 @@ private function jobMockWithAttemptsAndCustomParameters(
;
$job->expects($this->once())
->method('export')
- ->willReturn($parameters);
+ ->willReturn($parameters)
+ ;
return $job;
}
diff --git a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
index 09d8ae91..553a26a6 100644
--- a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
+++ b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
@@ -139,7 +139,8 @@ private function jobFailedWithException($exception)
$jobAfterFailure
->expects($this->any())
->method('causeOfFailure')
- ->will($this->returnValue($exception));
+ ->will($this->returnValue($exception))
+ ;
return $jobAfterFailure;
}
diff --git a/spec/Recruiter/RetryPolicy/TimeTableTest.php b/spec/Recruiter/RetryPolicy/TimeTableTest.php
index d5361aaa..a4bd304a 100644
--- a/spec/Recruiter/RetryPolicy/TimeTableTest.php
+++ b/spec/Recruiter/RetryPolicy/TimeTableTest.php
@@ -136,7 +136,8 @@ private function jobThatWasCreated($relativeTime)
;
$job->expects($this->any())
->method('createdAt')
- ->will($this->returnValue($wasCreatedAt));
+ ->will($this->returnValue($wasCreatedAt))
+ ;
return $job;
}
From 6e642792598c64030412e4f1809aba760a17cb93 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 14:17:05 +0200
Subject: [PATCH 29/59] Fix most of the tests
---
.../JobCallCustomMethodOnWorkableTest.php | 2 +-
.../Recruiter/JobSendEventsToWorkableTest.php | 32 ++++---
...keRetryPolicyFromRetriableWorkableTest.php | 1 +
spec/Recruiter/PickAvailableWorkersTest.php | 87 ++++++++++++++++---
.../Command/Bko/AnalyticsCommand.php | 2 +-
5 files changed, 97 insertions(+), 27 deletions(-)
diff --git a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
index b3a9d522..c96374ab 100644
--- a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
+++ b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
@@ -16,7 +16,7 @@ class JobCallCustomMethodOnWorkableTest extends TestCase
protected function setUp(): void
{
$this->workable = $this
- ->getMockBuilder(Workable::class)
+ ->getMockBuilder(DummyWorkableWithSendCustomMethod::class)
->onlyMethods(['export', 'import', 'asJobOf', 'send'])
->getMock()
;
diff --git a/spec/Recruiter/JobSendEventsToWorkableTest.php b/spec/Recruiter/JobSendEventsToWorkableTest.php
index 4bbb0c19..8bceaed7 100644
--- a/spec/Recruiter/JobSendEventsToWorkableTest.php
+++ b/spec/Recruiter/JobSendEventsToWorkableTest.php
@@ -2,7 +2,6 @@
namespace Recruiter;
-use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Recruiter\Job\Event;
@@ -26,25 +25,19 @@ protected function setUp(): void
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
}
- /**
- * @throws Exception
- */
public function testTakeRetryPolicyFromRetriableInstance()
{
- $listener = $this->createPartialMock(EventListener::class, ['onEvent']);
- $listener
- ->expects($this->exactly(3))
- ->method('onEvent')
- ->withConsecutive(
- [$this->equalTo('job.started'), $this->anything()],
- [$this->equalTo('job.ended'), $this->anything()],
- [$this->equalTo('job.failure.last'), $this->anything()],
- )
- ;
+ $listener = new EventListenerSpy();
$workable = new WorkableThatIsAlsoAnEventListener($listener);
$job = Job::around($workable, $this->repository);
$job->execute($this->dispatcher);
+
+ $events = $listener->events;
+ $this->assertCount(3, $events);
+ $this->assertSame('job.started', $events[0][0]);
+ $this->assertSame('job.ended', $events[1][0]);
+ $this->assertSame('job.failure.last', $events[2][0]);
}
}
@@ -54,6 +47,7 @@ class WorkableThatIsAlsoAnEventListener implements Workable, EventListener
public function __construct(private readonly EventListener $listener)
{
+ $this->parameters = [];
}
public function onEvent($channel, Event $ev)
@@ -66,3 +60,13 @@ public function execute()
throw new \Exception();
}
}
+
+class EventListenerSpy implements EventListener
+{
+ public array $events = [];
+
+ public function onEvent($channel, Event $ev): void
+ {
+ $this->events[] = [$channel, $ev];
+ }
+}
diff --git a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
index e2939e21..5385ce19 100644
--- a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
+++ b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
@@ -46,6 +46,7 @@ class WorkableThatIsAlsoRetriable implements Workable, Retriable
public function __construct(private readonly RetryPolicy $retryWithPolicy)
{
+ $this->parameters = [];
}
public function retryWithPolicy(): RetryPolicy
diff --git a/spec/Recruiter/PickAvailableWorkersTest.php b/spec/Recruiter/PickAvailableWorkersTest.php
index 54abd630..13c96ea9 100644
--- a/spec/Recruiter/PickAvailableWorkersTest.php
+++ b/spec/Recruiter/PickAvailableWorkersTest.php
@@ -2,8 +2,12 @@
namespace Recruiter;
+use MongoDB\BSON\Int64;
use MongoDB\BSON\ObjectId;
use MongoDB\Collection;
+use MongoDB\Driver\CursorInterface;
+use MongoDB\Driver\Server;
+use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
@@ -12,14 +16,12 @@ class PickAvailableWorkersTest extends TestCase
private MockObject&Collection $repository;
private int $workersPerUnit;
+ /**
+ * @throws Exception
+ */
protected function setUp(): void
{
- $this->repository = $this
- ->getMockBuilder(Collection::class)
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
+ $this->repository = $this->createMock(Collection::class);
$this->workersPerUnit = 42;
}
@@ -32,7 +34,7 @@ public function testNoWorkersAreFound()
$this->assertEquals([], $picked);
}
- public function testFewWorkersWithNoSpecifiSkill()
+ public function testFewWorkersWithNoSpecificSkill(): void
{
$callbackHasBeenCalled = false;
$this->withAvailableWorkers(['*' => 3]);
@@ -41,7 +43,7 @@ public function testFewWorkersWithNoSpecifiSkill()
[$worksOn, $workers] = $picked[0];
$this->assertEquals('*', $worksOn);
- $this->assertEquals(3, count($workers));
+ $this->assertCount(3, $workers);
}
public function testFewWorkersWithSameSkill()
@@ -86,7 +88,10 @@ public function testMoreWorkersThanAllowedPerUnit()
$this->assertEquals($this->workersPerUnit, $totalWorkersGiven);
}
- private function withAvailableWorkers($workers)
+ /**
+ * @throws Exception
+ */
+ private function withAvailableWorkers($workers): void
{
$workersThatShouldBeFound = [];
foreach ($workers as $skill => $quantity) {
@@ -102,7 +107,7 @@ private function withAvailableWorkers($workers)
$this->repository
->expects($this->any())
->method('find')
- ->will($this->returnValue(new \ArrayIterator($workersThatShouldBeFound)))
+ ->willReturn(new FakeCursor($workersThatShouldBeFound))
;
}
@@ -111,7 +116,7 @@ private function withNoAvailableWorkers()
$this->repository
->expects($this->any())
->method('find')
- ->will($this->returnValue(new \ArrayIterator([])))
+ ->willReturn(new FakeCursor())
;
}
@@ -122,3 +127,63 @@ private function assertArrayAreEquals($expected, $given)
$this->assertEquals($expected, $given);
}
}
+
+class FakeCursor implements CursorInterface, \Iterator
+{
+ private array $data;
+
+ public function __construct(array $data = [])
+ {
+ $this->data = array_values($data);
+ }
+
+ public function getId(): Int64
+ {
+ return new Int64(42);
+ }
+
+ public function getServer(): Server
+ {
+ throw new \LogicException('Not implemented');
+ }
+
+ public function isDead(): bool
+ {
+ throw new \LogicException('Not implemented');
+ }
+
+ public function setTypeMap(array $typemap): void
+ {
+ throw new \LogicException('Not implemented');
+ }
+
+ public function toArray(): array
+ {
+ throw new \LogicException('Not implemented');
+ }
+
+ public function current(): object|array|null
+ {
+ return current($this->data);
+ }
+
+ public function next(): void
+ {
+ next($this->data);
+ }
+
+ public function key(): ?int
+ {
+ return key($this->data);
+ }
+
+ public function valid(): bool
+ {
+ return null !== key($this->data);
+ }
+
+ public function rewind(): void
+ {
+ reset($this->data);
+ }
+}
diff --git a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
index a569404b..5603ce6a 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
@@ -25,7 +25,7 @@ public function __construct(private readonly Factory $factory, private readonly
parent::__construct();
}
- protected function configure()
+ protected function configure(): void
{
$this
->setName('bko:analytics')
From 8129805fa2fad47954e6a10a83ad0ba1cba668a6 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 14:45:12 +0200
Subject: [PATCH 30/59] Update language level
---
spec/Recruiter/Acceptance/FaultToleranceTest.php | 2 +-
src/Recruiter/Workable/ThrowsFatalError.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index abe2bcfd..c4053ec8 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -63,7 +63,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies()
// executions. The problem is that the retry policy is
// evaluated after the execution but fatal errors are not
// catchable and so the job will stay scheduled forever
- (new ThrowsFatalError())
+ new ThrowsFatalError()
->asJobOf($this->recruiter)
->inBackground()
->retryWithPolicy(RetryManyTimes::forTimes(1, 0))
diff --git a/src/Recruiter/Workable/ThrowsFatalError.php b/src/Recruiter/Workable/ThrowsFatalError.php
index a80a0211..257cb523 100644
--- a/src/Recruiter/Workable/ThrowsFatalError.php
+++ b/src/Recruiter/Workable/ThrowsFatalError.php
@@ -9,7 +9,7 @@ class ThrowsFatalError implements Workable
{
use WorkableBehaviour;
- public function execute()
+ public function execute(): void
{
new ThisClassDoesnNotExists();
}
From 5e1405b916247f39860adb3e1079df30c9af94e8 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 15:02:58 +0200
Subject: [PATCH 31/59] Introduce URI::fromEnvironment
---
.../Acceptance/BaseAcceptanceTestCase.php | 3 +--
spec/Recruiter/FactoryTest.php | 2 +-
spec/Recruiter/Job/RepositoryTest.php | 2 +-
.../Command/Bko/AnalyticsCommand.php | 2 +-
.../Command/Bko/JobRecoverCommand.php | 2 +-
.../Command/Bko/RemoveSchedulerCommand.php | 2 +-
.../Infrastructure/Command/CleanerCommand.php | 3 +--
.../Command/RecruiterCommand.php | 3 +--
.../Infrastructure/Command/WorkerCommand.php | 3 +--
.../Persistence/Mongodb/URI.php | 26 +++++++++----------
10 files changed, 22 insertions(+), 26 deletions(-)
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index f88d26a1..fc526e25 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -32,8 +32,7 @@ abstract class BaseAcceptanceTestCase extends TestCase
protected function setUp(): void
{
$factory = new Factory();
- $uri = getenv('MONGODB_URI') ?: URI::DEFAULT_URI;
- $this->recruiterDb = $factory->getMongoDb(MongoURI::from($uri), []);
+ $this->recruiterDb = $factory->getMongoDb(URI::fromEnvironment(), []);
$this->cleanDb();
$this->files = ['/tmp/recruiter.log', '/tmp/worker.log'];
$this->cleanLogs();
diff --git a/spec/Recruiter/FactoryTest.php b/spec/Recruiter/FactoryTest.php
index b59ac993..3128cdc4 100644
--- a/spec/Recruiter/FactoryTest.php
+++ b/spec/Recruiter/FactoryTest.php
@@ -14,7 +14,7 @@ class FactoryTest extends TestCase
protected function setUp(): void
{
$this->factory = new Factory();
- $this->mongoURI = MongoURI::from(getenv('MONGODB_URI') ?: MongoURI::DEFAULT_URI);
+ $this->mongoURI = MongoURI::fromEnvironment();
}
public function testShouldCreateAMongoDatabaseConnection()
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index e6dc1a25..63c237ad 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -31,7 +31,7 @@ class RepositoryTest extends TestCase
protected function setUp(): void
{
$factory = new Factory();
- $this->recruiterDb = $factory->getMongoDb(MongoURI::from(getenv('MONGODB_URI') ?: MongoURI::DEFAULT_URI), []);
+ $this->recruiterDb = $factory->getMongoDb(MongoURI::fromEnvironment(), []);
$this->recruiterDb->drop();
$this->repository = new Repository($this->recruiterDb);
$this->clock = T\clock()->stop();
diff --git a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
index 5603ce6a..6c3c588c 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
@@ -35,7 +35,7 @@ protected function configure(): void
't',
InputOption::VALUE_REQUIRED,
'HOSTNAME[:PORT][/DB] MongoDB coordinates',
- 'mongodb://localhost:27017/recruiter',
+ MongoURI::fromEnvironment(),
)
->addOption(
'group',
diff --git a/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php b/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
index ff6b894f..46e53849 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
@@ -39,7 +39,7 @@ protected function configure()
't',
InputOption::VALUE_REQUIRED,
'HOSTNAME[:PORT][/DB] MongoDB coordinates',
- 'mongodb://localhost:27017/recruiter',
+ MongoURI::fromEnvironment(),
)
->addOption(
'scheduleAt',
diff --git a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
index 6cfca252..17d777eb 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
@@ -51,7 +51,7 @@ protected function configure()
't',
InputOption::VALUE_REQUIRED,
'HOSTNAME[:PORT][/DB] MongoDB coordinates',
- 'mongodb://localhost:27017/recruiter',
+ MongoURI::fromEnvironment(),
)
;
}
diff --git a/src/Recruiter/Infrastructure/Command/CleanerCommand.php b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
index a7ce29f6..8ea9053c 100644
--- a/src/Recruiter/Infrastructure/Command/CleanerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
@@ -124,8 +124,7 @@ public function description(): string
public function definition(): InputDefinition
{
- $defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
-
+ $defaultMongoUri = MongoURI::fromEnvironment();
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('clean-after', 'c', InputOption::VALUE_REQUIRED, 'delete jobs after :period', '5days'),
diff --git a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
index ee06dd98..46f3903d 100644
--- a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
+++ b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
@@ -177,8 +177,7 @@ public function description(): string
public function definition(): InputDefinition
{
- $defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
-
+ $defaultMongoUri = MongoURI::fromEnvironment();
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling (milliseconds)', '1600ms'),
diff --git a/src/Recruiter/Infrastructure/Command/WorkerCommand.php b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
index 85447cb9..a96abd90 100644
--- a/src/Recruiter/Infrastructure/Command/WorkerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
@@ -114,8 +114,7 @@ public function description(): string
public function definition(): InputDefinition
{
- $defaultMongoUri = getenv('MONGODB_URI') ?: 'mongodb://localhost:27017';
-
+ $defaultMongoUri = MongoURI::fromEnvironment();
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling', '6400ms'),
diff --git a/src/Recruiter/Infrastructure/Persistence/Mongodb/URI.php b/src/Recruiter/Infrastructure/Persistence/Mongodb/URI.php
index 46b21325..b76da40c 100644
--- a/src/Recruiter/Infrastructure/Persistence/Mongodb/URI.php
+++ b/src/Recruiter/Infrastructure/Persistence/Mongodb/URI.php
@@ -4,25 +4,25 @@
namespace Recruiter\Infrastructure\Persistence\Mongodb;
-/**
- * Class URI.
- */
-class URI
+final readonly class URI implements \Stringable
{
- public const DEFAULT_URI = 'mongodb://127.0.0.1:27017/recruiter';
+ public const string DEFAULT_URI = 'mongodb://127.0.0.1:27017/recruiter';
- /**
- * @var string
- */
- private $uri;
+ public function __construct(private string $uri)
+ {
+ }
- public function __construct(string $uri)
+ public static function fromEnvironment(): self
{
- $this->uri = $uri;
+ return self::from(getenv('MONGODB_URI'));
}
- public static function from(?string $uri): self
+ public static function from(string|self|null $uri): self
{
+ if ($uri instanceof self) {
+ return $uri;
+ }
+
if (!$uri) {
$uri = self::DEFAULT_URI;
}
@@ -40,7 +40,7 @@ public function database(): string
return substr($parsed['path'], 1);
}
- public function __toString()
+ public function __toString(): string
{
return $this->uri;
}
From 6ce9d2abb3147c71ad5b747b1b8a1adb0302235d Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 15:08:30 +0200
Subject: [PATCH 32/59] Fix outdated examples
---
examples/bootstrap.php | 10 ++++++--
examples/jobAndWorkerTagged.php | 14 +++++------
...obFailedBecauseOfNonRetriableException.php | 24 +++++++++----------
examples/jobRetriedManyTimesUntilArchived.php | 24 +++++++++----------
examples/oneTimeJob.php | 14 +++++------
5 files changed, 46 insertions(+), 40 deletions(-)
diff --git a/examples/bootstrap.php b/examples/bootstrap.php
index c61635fd..bbc2269c 100644
--- a/examples/bootstrap.php
+++ b/examples/bootstrap.php
@@ -1,6 +1,12 @@
getEventDispatcher()->addListener('job.failure.last', function($event): void {
- error_log("Job definitively failed: " . var_export($event->export(), true));
+
+global $recruiter;
+assert($recruiter instanceof Recruiter);
+
+$recruiter->getEventDispatcher()->addListener('job.failure.last', function ($event): void {
+ error_log('Job definitively failed: ' . var_export($event->export(), true));
});
diff --git a/examples/jobAndWorkerTagged.php b/examples/jobAndWorkerTagged.php
index 632e2238..d8795837 100755
--- a/examples/jobAndWorkerTagged.php
+++ b/examples/jobAndWorkerTagged.php
@@ -3,17 +3,16 @@
require __DIR__ . '/../vendor/autoload.php';
-use Recruiter\Recruiter;
use Recruiter\Factory;
+use Recruiter\Infrastructure\Memory\MemoryLimit;
+use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
+use Recruiter\Recruiter;
use Recruiter\Workable\LazyBones;
-use Recruiter\Worker;
-use Recruiter\Option\MemoryLimit;
$factory = new Factory();
$db = $factory->getMongoDb(
- $hosts = 'localhost:27017',
+ MongoURI::fromEnvironment(),
$options = [],
- $dbName = 'recruiter'
);
$db->drop();
@@ -23,9 +22,10 @@
->asJobOf($recruiter)
->inGroup('mail')
->inBackground()
- ->execute();
+ ->execute()
+;
-$memoryLimit = new MemoryLimit('memory-limit', '64MB');
+$memoryLimit = new MemoryLimit('64MB');
$worker = $recruiter->hire($memoryLimit);
$worker->workOnJobsGroupedAs('mail');
$assignments = $recruiter->assignJobsToWorkers();
diff --git a/examples/jobFailedBecauseOfNonRetriableException.php b/examples/jobFailedBecauseOfNonRetriableException.php
index a1e452c3..96f6aef7 100755
--- a/examples/jobFailedBecauseOfNonRetriableException.php
+++ b/examples/jobFailedBecauseOfNonRetriableException.php
@@ -3,20 +3,17 @@
require __DIR__ . '/../vendor/autoload.php';
-use Timeless as T;
-
-use Recruiter\Recruiter;
use Recruiter\Factory;
+use Recruiter\Infrastructure\Memory\MemoryLimit;
+use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
+use Recruiter\Recruiter;
use Recruiter\Workable\AlwaysFail;
-use Recruiter\RetryPolicy;
-use Recruiter\Worker;
-use Recruiter\Option\MemoryLimit;
+use Timeless as T;
$factory = new Factory();
$db = $factory->getMongoDb(
- $hosts = 'localhost:27017',
+ MongoURI::fromEnvironment(),
$options = [],
- $dbName = 'recruiter'
);
$db->drop();
@@ -24,16 +21,19 @@
(new AlwaysFail())
->asJobOf($recruiter)
- ->retryManyTimes(5, T\seconds(1), 'DomainException')
+ ->retryManyTimes(5, T\seconds(1), DomainException::class)
->inBackground()
- ->execute();
+ ->execute()
+;
-$memoryLimit = new MemoryLimit('memory-limit', '64MB');
+$memoryLimit = new MemoryLimit('64MB');
$worker = $recruiter->hire($memoryLimit);
while (true) {
printf("Try to do my work\n");
$assignments = $recruiter->assignJobsToWorkers();
- if ($assignments === 0) break;
+ if (0 === $assignments) {
+ break;
+ }
$worker->work();
usleep(1200 * 1000);
}
diff --git a/examples/jobRetriedManyTimesUntilArchived.php b/examples/jobRetriedManyTimesUntilArchived.php
index e713e515..8972afcc 100755
--- a/examples/jobRetriedManyTimesUntilArchived.php
+++ b/examples/jobRetriedManyTimesUntilArchived.php
@@ -3,37 +3,37 @@
require __DIR__ . '/../vendor/autoload.php';
-use Timeless as T;
-
-use Recruiter\Recruiter;
use Recruiter\Factory;
+use Recruiter\Infrastructure\Memory\MemoryLimit;
+use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
+use Recruiter\Recruiter;
use Recruiter\Workable\AlwaysFail;
-use Recruiter\RetryPolicy;
-use Recruiter\Worker;
-use Recruiter\Option\MemoryLimit;
+use Timeless as T;
$factory = new Factory();
$db = $factory->getMongoDb(
- $hosts = 'localhost:27017',
+ MongoURI::fromEnvironment(),
$options = [],
- $dbName = 'recruiter'
);
$db->drop();
$recruiter = new Recruiter($db);
-(new AlwaysFail())
+new AlwaysFail()
->asJobOf($recruiter)
->retryManyTimes(5, T\second(1))
->inBackground()
- ->execute();
+ ->execute()
+;
-$memoryLimit = new MemoryLimit('memory-limit', '64MB');
+$memoryLimit = new MemoryLimit('64MB');
$worker = $recruiter->hire($memoryLimit);
while (true) {
printf("Try to do my work\n");
$assignments = $recruiter->assignJobsToWorkers();
- if ($assignments === 0) break;
+ if (0 === count($assignments)) {
+ break;
+ }
$worker->work();
usleep(1200 * 1000);
}
diff --git a/examples/oneTimeJob.php b/examples/oneTimeJob.php
index 16561ff9..54a15ecb 100755
--- a/examples/oneTimeJob.php
+++ b/examples/oneTimeJob.php
@@ -3,17 +3,16 @@
require __DIR__ . '/../vendor/autoload.php';
-use Recruiter\Recruiter;
use Recruiter\Factory;
+use Recruiter\Infrastructure\Memory\MemoryLimit;
+use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
+use Recruiter\Recruiter;
use Recruiter\Workable\LazyBones;
-use Recruiter\Worker;
-use Recruiter\Option\MemoryLimit;
$factory = new Factory();
$db = $factory->getMongoDb(
- $hosts = 'localhost:27017',
+ MongoURI::fromEnvironment(),
$options = [],
- $dbName = 'recruiter'
);
$db->drop();
@@ -22,9 +21,10 @@
LazyBones::waitForMs(200, 100)
->asJobOf($recruiter)
->inBackground()
- ->execute();
+ ->execute()
+;
-$memoryLimit = new MemoryLimit('memory-limit', '64MB');
+$memoryLimit = new MemoryLimit('64MB');
$worker = $recruiter->hire($memoryLimit);
$assignments = $recruiter->assignJobsToWorkers();
$worker->work();
From 5bdf1ce158b65f4d359eba176387627dbdf79f65 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 15:15:55 +0200
Subject: [PATCH 33/59] Ad explicit cast to string
---
src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php | 2 +-
src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php | 2 +-
.../Infrastructure/Command/Bko/RemoveSchedulerCommand.php | 2 +-
src/Recruiter/Infrastructure/Command/CleanerCommand.php | 2 +-
src/Recruiter/Infrastructure/Command/RecruiterCommand.php | 2 +-
src/Recruiter/Infrastructure/Command/WorkerCommand.php | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
index 6c3c588c..e29aec32 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
@@ -35,7 +35,7 @@ protected function configure(): void
't',
InputOption::VALUE_REQUIRED,
'HOSTNAME[:PORT][/DB] MongoDB coordinates',
- MongoURI::fromEnvironment(),
+ (string) MongoURI::fromEnvironment(),
)
->addOption(
'group',
diff --git a/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php b/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
index 46e53849..960ba347 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/JobRecoverCommand.php
@@ -39,7 +39,7 @@ protected function configure()
't',
InputOption::VALUE_REQUIRED,
'HOSTNAME[:PORT][/DB] MongoDB coordinates',
- MongoURI::fromEnvironment(),
+ (string) MongoURI::fromEnvironment(),
)
->addOption(
'scheduleAt',
diff --git a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
index 17d777eb..a81bd66a 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
@@ -51,7 +51,7 @@ protected function configure()
't',
InputOption::VALUE_REQUIRED,
'HOSTNAME[:PORT][/DB] MongoDB coordinates',
- MongoURI::fromEnvironment(),
+ (string) MongoURI::fromEnvironment(),
)
;
}
diff --git a/src/Recruiter/Infrastructure/Command/CleanerCommand.php b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
index 8ea9053c..932c9b05 100644
--- a/src/Recruiter/Infrastructure/Command/CleanerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
@@ -124,7 +124,7 @@ public function description(): string
public function definition(): InputDefinition
{
- $defaultMongoUri = MongoURI::fromEnvironment();
+ $defaultMongoUri = (string) MongoURI::fromEnvironment();
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('clean-after', 'c', InputOption::VALUE_REQUIRED, 'delete jobs after :period', '5days'),
diff --git a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
index 46f3903d..027f7f01 100644
--- a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
+++ b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
@@ -177,7 +177,7 @@ public function description(): string
public function definition(): InputDefinition
{
- $defaultMongoUri = MongoURI::fromEnvironment();
+ $defaultMongoUri = (string) MongoURI::fromEnvironment();
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling (milliseconds)', '1600ms'),
diff --git a/src/Recruiter/Infrastructure/Command/WorkerCommand.php b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
index a96abd90..5ba1fd2b 100644
--- a/src/Recruiter/Infrastructure/Command/WorkerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
@@ -114,7 +114,7 @@ public function description(): string
public function definition(): InputDefinition
{
- $defaultMongoUri = MongoURI::fromEnvironment();
+ $defaultMongoUri = (string) MongoURI::fromEnvironment();
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling', '6400ms'),
From a77993c1d286c8b326a137dfdf41e78e43a5d565 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 15:34:58 +0200
Subject: [PATCH 34/59] Fix some type hints and errors
---
phpstan.neon | 2 --
src/Recruiter/Factory.php | 3 ++-
src/Recruiter/Workable/ThrowsFatalError.php | 1 +
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/phpstan.neon b/phpstan.neon
index e80c96d0..3bb2b042 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -6,10 +6,8 @@ parameters:
scanDirectories:
- %currentWorkingDirectory%/vendor/giorgiosironi/eris/src/
ignoreErrors:
- - '#Instantiated class Recruiter\\Workable\\ThisClassDoesnNotExists not found.#'
- '#Function recruiter_became_master not found.#'
- '#Function recruiter_stept_back not found.#'
- '#Unsafe usage of new static\(\).#'
- '#Call to an undefined static method Sink\\BlackHole::whateverStaticMethod\(\).#'
- - '#Constructor of class Recruiter\\Workable\\FailsInConstructor has an unused parameter \$parameters.#'
inferPrivatePropertyTypeFromConstructor: true
diff --git a/src/Recruiter/Factory.php b/src/Recruiter/Factory.php
index d8164685..f863c0c5 100644
--- a/src/Recruiter/Factory.php
+++ b/src/Recruiter/Factory.php
@@ -3,12 +3,13 @@
namespace Recruiter;
use MongoDB\Client;
+use MongoDB\Database;
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
use Recruiter\Infrastructure\Persistence\Mongodb\URI;
class Factory
{
- public function getMongoDb(URI $uri, array $options = [])
+ public function getMongoDb(URI $uri, array $options = []): Database
{
try {
$optionsWithMajorityConcern = ['w' => 'majority'];
diff --git a/src/Recruiter/Workable/ThrowsFatalError.php b/src/Recruiter/Workable/ThrowsFatalError.php
index 257cb523..e86b0996 100644
--- a/src/Recruiter/Workable/ThrowsFatalError.php
+++ b/src/Recruiter/Workable/ThrowsFatalError.php
@@ -11,6 +11,7 @@ class ThrowsFatalError implements Workable
public function execute(): void
{
+ /** @phpstan-ignore-next-line */
new ThisClassDoesnNotExists();
}
}
From 7cdcd5d1183141c01c581619be6fc325d420ae74 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 15:35:27 +0200
Subject: [PATCH 35/59] Fix Coding Standards
---
spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php | 1 -
src/Recruiter/Infrastructure/Command/CleanerCommand.php | 1 +
src/Recruiter/Infrastructure/Command/RecruiterCommand.php | 1 +
src/Recruiter/Infrastructure/Command/WorkerCommand.php | 1 +
4 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index fc526e25..5845b8bc 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -8,7 +8,6 @@
use Recruiter\Concurrency\Timeout;
use Recruiter\Factory;
use Recruiter\Infrastructure\Persistence\Mongodb\URI;
-use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
use Recruiter\Recruiter;
use Recruiter\RetryPolicy;
use Recruiter\Workable\ShellCommand;
diff --git a/src/Recruiter/Infrastructure/Command/CleanerCommand.php b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
index 932c9b05..cbf85798 100644
--- a/src/Recruiter/Infrastructure/Command/CleanerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
@@ -125,6 +125,7 @@ public function description(): string
public function definition(): InputDefinition
{
$defaultMongoUri = (string) MongoURI::fromEnvironment();
+
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('clean-after', 'c', InputOption::VALUE_REQUIRED, 'delete jobs after :period', '5days'),
diff --git a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
index 027f7f01..67b907f5 100644
--- a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
+++ b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
@@ -178,6 +178,7 @@ public function description(): string
public function definition(): InputDefinition
{
$defaultMongoUri = (string) MongoURI::fromEnvironment();
+
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling (milliseconds)', '1600ms'),
diff --git a/src/Recruiter/Infrastructure/Command/WorkerCommand.php b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
index 5ba1fd2b..d9c1331f 100644
--- a/src/Recruiter/Infrastructure/Command/WorkerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
@@ -115,6 +115,7 @@ public function description(): string
public function definition(): InputDefinition
{
$defaultMongoUri = (string) MongoURI::fromEnvironment();
+
return new InputDefinition([
new InputOption('target', 't', InputOption::VALUE_REQUIRED, 'HOSTNAME[:PORT][/DB] MongoDB coordinates', $defaultMongoUri),
new InputOption('backoff-to', 'b', InputOption::VALUE_REQUIRED, 'Upper limit of time to wait before next polling', '6400ms'),
From a47bfa9a1e82d936484bf71bb8be4ef3a185b517 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 15:51:17 +0200
Subject: [PATCH 36/59] Add some type hints
---
src/Recruiter/JobAfterFailure.php | 32 +++++++++++--------------------
1 file changed, 11 insertions(+), 21 deletions(-)
diff --git a/src/Recruiter/JobAfterFailure.php b/src/Recruiter/JobAfterFailure.php
index ba6fdd93..4d552651 100644
--- a/src/Recruiter/JobAfterFailure.php
+++ b/src/Recruiter/JobAfterFailure.php
@@ -7,50 +7,40 @@
class JobAfterFailure
{
- /** @var Job */
- private $job;
+ private bool $hasBeenScheduled;
- /** @var JobExecution */
- private $lastJobExecution;
+ private bool $hasBeenArchived;
- /** @var bool */
- private $hasBeenScheduled;
-
- /** @var bool */
- private $hasBeenArchived;
-
- public function __construct(Job $job, JobExecution $lastJobExecution)
+ public function __construct(private readonly Job $job, private readonly JobExecution $lastJobExecution)
{
- $this->job = $job;
- $this->lastJobExecution = $lastJobExecution;
$this->hasBeenScheduled = false;
$this->hasBeenArchived = false;
}
- public function createdAt()
+ public function createdAt(): Moment
{
return $this->job->createdAt();
}
- public function inGroup($group)
+ public function inGroup($group): void
{
$this->job->inGroup($group);
$this->job->save();
}
- public function scheduleIn(Interval $in)
+ public function scheduleIn(Interval $in): void
{
$this->scheduleAt($in->fromNow());
}
- public function scheduleAt(Moment $at)
+ public function scheduleAt(Moment $at): void
{
$this->hasBeenScheduled = true;
$this->job->scheduleAt($at);
$this->job->save();
}
- public function archive($why)
+ public function archive($why): void
{
$this->hasBeenArchived = true;
$this->job->archive($why);
@@ -61,7 +51,7 @@ public function causeOfFailure()
return $this->lastJobExecution->causeOfFailure();
}
- public function lastExecutionDuration()
+ public function lastExecutionDuration(): Interval
{
return $this->lastJobExecution->duration();
}
@@ -71,7 +61,7 @@ public function numberOfAttempts()
return $this->job->numberOfAttempts();
}
- public function archiveIfNotScheduled()
+ public function archiveIfNotScheduled(): bool
{
if (!$this->hasBeenScheduled && !$this->hasBeenArchived) {
$this->archive('not-scheduled-by-retry-policy');
@@ -82,7 +72,7 @@ public function archiveIfNotScheduled()
return false;
}
- public function hasBeenArchived()
+ public function hasBeenArchived(): bool
{
return $this->hasBeenArchived;
}
From 98b908aecf426a4314a97848aaaffc13a836075d Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 21:16:52 +0200
Subject: [PATCH 37/59] Move further steps with rector
---
...obFailedBecauseOfNonRetriableException.php | 2 +-
rector.php | 6 +-
.../Acceptance/BaseAcceptanceTestCase.php | 4 +-
spec/Recruiter/Acceptance/EnduranceTest.php | 75 ++++++++-----------
.../Acceptance/FaultToleranceTest.php | 12 +--
spec/Recruiter/Acceptance/HooksTest.php | 29 +++----
.../RepeatableJobsAreScheduledTest.php | 20 +++--
.../Acceptance/SyncronousExecutionTest.php | 6 +-
...rGuaranteedToExitWhenAMemoryLeakOccurs.php | 6 +-
...itWithFailureCodeInCaseOfExceptionTest.php | 4 +-
...WorkerGuaranteedToRetireAfterDeathTest.php | 2 +-
.../Acceptance/WorkerRepositoryTest.php | 3 +-
spec/Recruiter/CleanerTest.php | 6 +-
spec/Recruiter/ExampleTest.php | 2 +-
spec/Recruiter/FactoryTest.php | 8 +-
...rkableImplementsFinalizerInterfaceTest.php | 21 ++----
.../Infrastructure/Memory/MemoryLimitTest.php | 2 +-
spec/Recruiter/Job/EventTest.php | 6 +-
spec/Recruiter/Job/RepositoryTest.php | 30 ++++----
.../JobCallCustomMethodOnWorkableTest.php | 8 +-
.../Recruiter/JobSendEventsToWorkableTest.php | 8 +-
...keRetryPolicyFromRetriableWorkableTest.php | 4 +-
spec/Recruiter/JobTest.php | 6 +-
.../JobToBePassedRetryStatisticsTest.php | 2 +-
spec/Recruiter/JobToScheduleTest.php | 42 +++++------
spec/Recruiter/PickAvailableWorkersTest.php | 8 +-
.../RetryPolicy/ExponentialBackoffTest.php | 8 +-
.../RetriableExceptionFilterTest.php | 24 +++---
.../RetryPolicy/SelectByExceptionTest.php | 10 +--
spec/Recruiter/RetryPolicy/TimeTableTest.php | 24 +++---
spec/Recruiter/SchedulePolicy/CronTest.php | 2 +-
spec/Recruiter/TaggableWorkableTest.php | 19 ++---
spec/Recruiter/WaitStrategyTest.php | 12 +--
.../Workable/FactoryMethodCommandTest.php | 6 +-
spec/Recruiter/Workable/ShellCommandTest.php | 4 +-
spec/Recruiter/WorkablePersistenceTest.php | 2 +-
spec/Recruiter/WorkerProcessTest.php | 8 +-
spec/Sink/BlackHoleTest.php | 32 ++++----
spec/Timeless/IntervalFormatTest.php | 4 +-
spec/Timeless/IntervalParseTest.php | 10 +--
spec/Timeless/MongoDateTest.php | 2 +-
src/Recruiter/Cleaner.php | 8 +-
src/Recruiter/Finalizable.php | 8 +-
src/Recruiter/FinalizableBehaviour.php | 8 +-
.../Command/Bko/AnalyticsCommand.php | 4 +-
.../Command/Bko/RemoveSchedulerCommand.php | 14 +---
.../Infrastructure/Command/CleanerCommand.php | 45 ++---------
.../Command/RecruiterCommand.php | 47 ++----------
.../Infrastructure/Command/WorkerCommand.php | 13 +---
.../Filesystem/BootstrapFile.php | 15 +---
src/Recruiter/Job.php | 43 ++++++-----
src/Recruiter/Job/EventListener.php | 2 +-
src/Recruiter/JobExecution.php | 36 ++++-----
src/Recruiter/JobToSchedule.php | 24 +++---
src/Recruiter/Recruiter.php | 67 ++++++++---------
src/Recruiter/RepeatableInJob.php | 2 +-
src/Recruiter/RetryPolicy.php | 4 +-
src/Recruiter/RetryPolicy/DoNotDoItAgain.php | 2 +-
.../RetryPolicy/ExponentialBackoff.php | 17 ++---
.../RetryPolicy/RetriableException.php | 6 +-
.../RetryPolicy/RetriableExceptionFilter.php | 14 ++--
src/Recruiter/RetryPolicy/RetryForever.php | 8 +-
src/Recruiter/RetryPolicy/RetryManyTimes.php | 11 ++-
.../RetryPolicy/SelectByException.php | 32 ++++----
src/Recruiter/RetryPolicy/TimeTable.php | 22 +++---
src/Recruiter/RetryPolicyBehaviour.php | 2 +-
src/Recruiter/RetryPolicyInJob.php | 2 +-
src/Recruiter/SchedulePolicy/Cron.php | 7 +-
src/Recruiter/SchedulePolicyInJob.php | 2 +-
src/Recruiter/Scheduler.php | 28 +------
src/Recruiter/Scheduler/Repository.php | 12 ++-
src/Recruiter/SynchronousExecutionReport.php | 12 +--
src/Recruiter/Taggable.php | 4 +-
src/Recruiter/WaitStrategy.php | 4 +-
src/Recruiter/Workable/AlwaysFail.php | 2 +-
.../Workable/FactoryMethodCommand.php | 11 +--
src/Recruiter/Workable/LazyBones.php | 2 +-
.../RecoverRepeatableFromException.php | 11 +--
.../Workable/RecoverWorkableFromException.php | 11 +--
.../Workable/SampleRepeatableCommand.php | 2 +-
src/Recruiter/Workable/ShellCommand.php | 5 +-
src/Recruiter/WorkableBehaviour.php | 2 +-
src/Recruiter/WorkableInJob.php | 2 +-
src/Recruiter/Worker.php | 27 ++-----
src/Recruiter/Worker/Process.php | 13 ++--
src/Recruiter/Worker/Repository.php | 4 +-
src/Recruiter/functions.php | 4 +-
src/Sink/BlackHole.php | 2 +-
88 files changed, 449 insertions(+), 663 deletions(-)
diff --git a/examples/jobFailedBecauseOfNonRetriableException.php b/examples/jobFailedBecauseOfNonRetriableException.php
index 96f6aef7..18e088bf 100755
--- a/examples/jobFailedBecauseOfNonRetriableException.php
+++ b/examples/jobFailedBecauseOfNonRetriableException.php
@@ -19,7 +19,7 @@
$recruiter = new Recruiter($db);
-(new AlwaysFail())
+new AlwaysFail()
->asJobOf($recruiter)
->retryManyTimes(5, T\seconds(1), DomainException::class)
->inBackground()
diff --git a/rector.php b/rector.php
index b2252895..1d25ee45 100644
--- a/rector.php
+++ b/rector.php
@@ -11,7 +11,7 @@
__DIR__ . '/src',
])
// uncomment to reach your current PHP version
- // ->withPhpSets()
- ->withTypeCoverageLevel(0)
+ ->withPhpSets()
+ ->withTypeCoverageLevel(2)
->withDeadCodeLevel(0)
- ->withCodeQualityLevel(0);
+ ->withCodeQualityLevel(1);
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index 5845b8bc..11ec14dd 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -171,9 +171,7 @@ protected function stopProcessWithSignal(array $processAndPipes, $signal): void
[$process, $pipes, $name] = $processAndPipes;
proc_terminate($process, $signal);
$this->lastStatus = proc_get_status($process);
- Timeout::inSeconds(30, function () use ($signal) {
- return 'termination of process: ' . var_export($this->lastStatus, true) . " after sending the `$signal` signal to it";
- })
+ Timeout::inSeconds(30, fn () => 'termination of process: ' . var_export($this->lastStatus, true) . " after sending the `$signal` signal to it")
->until(function () use ($process) {
$this->lastStatus = proc_get_status($process);
diff --git a/spec/Recruiter/Acceptance/EnduranceTest.php b/spec/Recruiter/Acceptance/EnduranceTest.php
index a0406630..650bb6ee 100644
--- a/spec/Recruiter/Acceptance/EnduranceTest.php
+++ b/spec/Recruiter/Acceptance/EnduranceTest.php
@@ -19,6 +19,7 @@ class EnduranceTest extends BaseAcceptanceTestCase
private Repository $jobRepository;
private string $actionLog;
+ #[\Override]
protected function setUp(): void
{
parent::setUp();
@@ -27,51 +28,43 @@ protected function setUp(): void
$this->files[] = $this->actionLog;
}
- public function testNotWithstandingCrashesJobsAreEventuallyPerformed()
+ public function testNotWithstandingCrashesJobsAreEventuallyPerformed(): void
{
$this
->limitTo(100)
->forAll(
Generator\bind(
Generator\choose(1, 4),
- function ($workers) {
- return Generator\tuple(
- Generator\constant($workers),
- Generator\seq(Generator\oneOf(
- Generator\map(
- function ($durationAndTag) {
- [$duration, $tag] = $durationAndTag;
+ fn ($workers) => Generator\tuple(
+ Generator\constant($workers),
+ Generator\seq(Generator\oneOf(
+ Generator\map(
+ function ($durationAndTag) {
+ [$duration, $tag] = $durationAndTag;
- return ['enqueueJob', $duration, $tag];
- },
- Generator\tuple(
- Generator\nat(),
- Generator\elements(['generic', 'fast-lane']),
- ),
+ return ['enqueueJob', $duration, $tag];
+ },
+ Generator\tuple(
+ Generator\nat(),
+ Generator\elements(['generic', 'fast-lane']),
),
- Generator\map(
- function ($workerIndex) {
- return ['restartWorkerGracefully', $workerIndex];
- },
- Generator\choose(0, $workers - 1),
- ),
- Generator\map(
- function ($workerIndex) {
- return ['restartWorkerByKilling', $workerIndex];
- },
- Generator\choose(0, $workers - 1),
- ),
- Generator\constant('restartRecruiterGracefully'),
- Generator\constant('restartRecruiterByKilling'),
- Generator\map(
- function ($milliseconds) {
- return ['sleep', $milliseconds];
- },
- Generator\choose(1, 1000),
- ),
- )),
- );
- },
+ ),
+ Generator\map(
+ fn ($workerIndex) => ['restartWorkerGracefully', $workerIndex],
+ Generator\choose(0, $workers - 1),
+ ),
+ Generator\map(
+ fn ($workerIndex) => ['restartWorkerByKilling', $workerIndex],
+ Generator\choose(0, $workers - 1),
+ ),
+ Generator\constant('restartRecruiterGracefully'),
+ Generator\constant('restartRecruiterByKilling'),
+ Generator\map(
+ fn ($milliseconds) => ['sleep', $milliseconds],
+ Generator\choose(1, 1000),
+ ),
+ )),
+ ),
),
)
->hook(Listener\log('/tmp/recruiter-test-iterations.log'))
@@ -98,13 +91,9 @@ function ($milliseconds) {
$estimatedTime = max(count($actions) * 4, 60);
Timeout::inSeconds(
$estimatedTime,
- function () {
- return "all $this->jobs jobs to be performed. Now is " . date('c') . ' Logs: ' . $this->files();
- },
+ fn () => "all $this->jobs jobs to be performed. Now is " . date('c') . ' Logs: ' . $this->files(),
)
- ->until(function () {
- return $this->jobRepository->countArchived() === $this->jobs;
- })
+ ->until(fn () => $this->jobRepository->countArchived() === $this->jobs)
;
$at = T\now();
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index c4053ec8..6c1140c7 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -10,7 +10,7 @@
class FaultToleranceTest extends BaseAcceptanceTestCase
{
- public function testRecruiterCrashAfterLockingJobsBeforeAssignmentAndIsRestarted()
+ public function testRecruiterCrashAfterLockingJobsBeforeAssignmentAndIsRestarted(): void
{
$memoryLimit = new MemoryLimit('64MB');
$this->enqueueJob();
@@ -22,9 +22,9 @@ public function testRecruiterCrashAfterLockingJobsBeforeAssignmentAndIsRestarted
$this->assertEquals(1, $totalNumber);
}
- public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor()
+ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor(): void
{
- (new FailsInConstructor([], false))
+ new FailsInConstructor([], false)
->asJobOf($this->recruiter)
->inBackground()
->retryWithPolicy(RetryManyTimes::forTimes(1, 0))
@@ -39,7 +39,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor()
sleep(2);
$jobDocument = current($this->scheduled->find()->toArray());
$this->assertEquals(1, $jobDocument['attempts']);
- $this->assertEquals('Recruiter\Workable\FailsInConstructor', $jobDocument['workable']['class']);
+ $this->assertEquals(FailsInConstructor::class, $jobDocument['workable']['class']);
$this->assertStringContainsString('This job failed while instantiating a workable', $jobDocument['last_execution']['message']);
$this->assertStringContainsString('I am supposed to fail in constructor code for testing purpose', $jobDocument['last_execution']['message']);
@@ -48,7 +48,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor()
sleep(2);
$jobDocument = current($this->archived->find()->toArray());
$this->assertEquals(2, $jobDocument['attempts']);
- $this->assertEquals('Recruiter\Workable\FailsInConstructor', $jobDocument['workable']['class']);
+ $this->assertEquals(FailsInConstructor::class, $jobDocument['workable']['class']);
$this->assertStringContainsString('This job failed while instantiating a workable', $jobDocument['last_execution']['message']);
$this->assertStringContainsString('I am supposed to fail in constructor code for testing purpose', $jobDocument['last_execution']['message']);
@@ -56,7 +56,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor()
$this->assertEquals(0, count($assignments));
}
- public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies()
+ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies(): void
{
// This job will fail with a fatal error and we want it to be
// retried at most 1 time, this means at most 2
diff --git a/spec/Recruiter/Acceptance/HooksTest.php b/spec/Recruiter/Acceptance/HooksTest.php
index 07b03d30..f52bb3ce 100644
--- a/spec/Recruiter/Acceptance/HooksTest.php
+++ b/spec/Recruiter/Acceptance/HooksTest.php
@@ -13,13 +13,14 @@ class HooksTest extends BaseAcceptanceTestCase
private MemoryLimit $memoryLimit;
private array $events;
+ #[\Override]
protected function setUp(): void
{
$this->memoryLimit = new MemoryLimit('64MB');
parent::setUp();
}
- public function testAfterFailureWithoutRetryEventIsFired()
+ public function testAfterFailureWithoutRetryEventIsFired(): void
{
$this->events = [];
$this->recruiter
@@ -32,7 +33,7 @@ function (Event $event): void {
)
;
- $job = (new AlwaysFail())
+ $job = new AlwaysFail()
->asJobOf($this->recruiter)
->inBackground()
->execute()
@@ -43,11 +44,11 @@ function (Event $event): void {
$worker->work();
$this->assertEquals(1, count($this->events));
- $this->assertInstanceOf('Recruiter\Job\Event', $this->events[0]);
+ $this->assertInstanceOf(Event::class, $this->events[0]);
$this->assertEquals('not-scheduled-by-retry-policy', $this->events[0]->export()['why']);
}
- public function testAfterLastFailureEventIsFired()
+ public function testAfterLastFailureEventIsFired(): void
{
$this->events = [];
$this->recruiter
@@ -60,7 +61,7 @@ function (Event $event): void {
)
;
- $job = (new AlwaysFail())
+ $job = new AlwaysFail()
->asJobOf($this->recruiter)
->retryWithPolicy(RetryManyTimes::forTimes(1, 0))
->inBackground()
@@ -81,11 +82,11 @@ function (Event $event): void {
$runAJob(2, $worker);
$this->assertEquals(1, count($this->events));
- $this->assertInstanceOf('Recruiter\Job\Event', $this->events[0]);
+ $this->assertInstanceOf(Event::class, $this->events[0]);
$this->assertEquals('tried-too-many-times', $this->events[0]->export()['why']);
}
- public function testJobStartedIsFired()
+ public function testJobStartedIsFired(): void
{
$this->events = [];
$this->recruiter
@@ -98,7 +99,7 @@ function (Event $event): void {
)
;
- $job = (new AlwaysSucceed())
+ $job = new AlwaysSucceed()
->asJobOf($this->recruiter)
->inBackground()
->execute()
@@ -109,10 +110,10 @@ function (Event $event): void {
$worker->work();
$this->assertEquals(1, count($this->events));
- $this->assertInstanceOf('Recruiter\Job\Event', $this->events[0]);
+ $this->assertInstanceOf(Event::class, $this->events[0]);
}
- public function testJobEndedIsFired()
+ public function testJobEndedIsFired(): void
{
$this->events = [];
$this->recruiter
@@ -125,13 +126,13 @@ function (Event $event): void {
)
;
- (new AlwaysSucceed())
+ new AlwaysSucceed()
->asJobOf($this->recruiter)
->inBackground()
->execute()
;
- (new AlwaysFail())
+ new AlwaysFail()
->asJobOf($this->recruiter)
->inBackground()
->execute()
@@ -144,7 +145,7 @@ function (Event $event): void {
$worker->work();
$this->assertEquals(2, count($this->events));
- $this->assertInstanceOf('Recruiter\Job\Event', $this->events[0]);
- $this->assertInstanceOf('Recruiter\Job\Event', $this->events[1]);
+ $this->assertInstanceOf(Event::class, $this->events[0]);
+ $this->assertInstanceOf(Event::class, $this->events[1]);
}
}
diff --git a/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php b/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
index e847ea58..f5d692cc 100644
--- a/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
+++ b/spec/Recruiter/Acceptance/RepeatableJobsAreScheduledTest.php
@@ -15,7 +15,7 @@ class RepeatableJobsAreScheduledTest extends BaseAcceptanceTestCase
{
use ArraySubsetAsserts;
- public function testARepeatableJobIsScheduledAtExpectedScheduledTime()
+ public function testARepeatableJobIsScheduledAtExpectedScheduledTime(): void
{
$expectedScheduleDate = strtotime('2019-05-16T14:00:00');
$schedulePolicy = new FixedSchedulePolicy($expectedScheduleDate);
@@ -34,7 +34,7 @@ public function testARepeatableJobIsScheduledAtExpectedScheduledTime()
'attempts' => 0,
'group' => 'generic',
'workable' => [
- 'class' => 'Recruiter\Workable\SampleRepeatableCommand',
+ 'class' => SampleRepeatableCommand::class,
'parameters' => [],
'method' => 'execute',
],
@@ -47,7 +47,7 @@ public function testARepeatableJobIsScheduledAtExpectedScheduledTime()
'executions' => 1,
],
'retry_policy' => [
- 'class' => 'Recruiter\RetryPolicy\ExponentialBackoff',
+ 'class' => ExponentialBackoff::class,
'parameters' => [
'retry_how_many_times' => 2,
'seconds_to_initially_wait_before_retry' => 5,
@@ -56,7 +56,7 @@ public function testARepeatableJobIsScheduledAtExpectedScheduledTime()
], $jobData);
}
- public function testOnlyASingleJobAreScheduledForTheSameSchedulingTime()
+ public function testOnlyASingleJobAreScheduledForTheSameSchedulingTime(): void
{
$expectedScheduleDate = strtotime('2019-05-16T14:00:00');
$schedulePolicy = new FixedSchedulePolicy($expectedScheduleDate);
@@ -75,7 +75,7 @@ public function testOnlyASingleJobAreScheduledForTheSameSchedulingTime()
);
}
- public function testAJobIsScheduledForEverySchedulingTime()
+ public function testAJobIsScheduledForEverySchedulingTime(): void
{
$expectedScheduleDates = [
strtotime('2019-05-16T14:00:00'),
@@ -93,7 +93,7 @@ public function testAJobIsScheduledForEverySchedulingTime()
$this->assertEquals(1, $jobs[1]->export()['scheduled']['executions']);
}
- public function testANewJobIsNotScheduledIfItShouldBeUniqueAndTheOldOneIsStillRunning()
+ public function testANewJobIsNotScheduledIfItShouldBeUniqueAndTheOldOneIsStillRunning(): void
{
$schedulePolicy = new FixedSchedulePolicy([
strtotime('2019-05-16T14:00:00'),
@@ -108,7 +108,7 @@ public function testANewJobIsNotScheduledIfItShouldBeUniqueAndTheOldOneIsStillRu
$this->assertEquals(1, count($jobs));
}
- public function testSchedulersAreUniqueOnUrn()
+ public function testSchedulersAreUniqueOnUrn(): void
{
$aSchedulerAlreadyHaveSomeAttempts = 3;
$this->IHaveAScheduleWithALongStory('unique-urn', $aSchedulerAlreadyHaveSomeAttempts);
@@ -149,7 +149,7 @@ private function scheduleAJob(string $urn, ?SchedulePolicy $schedulePolicy = nul
$schedulePolicy = new FixedSchedulePolicy(strtotime('2023-02-18T17:00:00'));
}
- $scheduler = (new SampleRepeatableCommand())
+ $scheduler = new SampleRepeatableCommand()
->asRepeatableJobOf($this->recruiter)
->repeatWithPolicy($schedulePolicy)
->retryWithPolicy(ExponentialBackoff::forTimes(2, 5))
@@ -185,16 +185,14 @@ private function fetchSchedulers()
class FixedSchedulePolicy implements SchedulePolicy
{
private array $timestamps;
- private int $index;
- public function __construct($timestamps, $index = 0)
+ public function __construct($timestamps, private int $index = 0)
{
if (!is_array($timestamps)) {
$timestamps = [$timestamps];
}
$this->timestamps = $timestamps;
- $this->index = $index;
}
public function next(): Moment
diff --git a/spec/Recruiter/Acceptance/SyncronousExecutionTest.php b/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
index 34f3dde6..382c0524 100644
--- a/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
+++ b/spec/Recruiter/Acceptance/SyncronousExecutionTest.php
@@ -8,7 +8,7 @@
class SyncronousExecutionTest extends BaseAcceptanceTestCase
{
- public function testJobsAreExecutedInOrderOfScheduling()
+ public function testJobsAreExecutedInOrderOfScheduling(): void
{
$this->enqueueAnAnswerJob(43, T\now()->after(T\seconds(30)));
@@ -22,9 +22,9 @@ public function testJobsAreExecutedInOrderOfScheduling()
$this->assertEquals(43, end($results)->result());
}
- public function testAReportIsReturnedInOrderToSortOutIfAnErrorOccured()
+ public function testAReportIsReturnedInOrderToSortOutIfAnErrorOccured(): void
{
- (new AlwaysFail())
+ new AlwaysFail()
->asJobOf($this->recruiter)
->inBackground()
->execute()
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
index 0ab1fb42..301363c5 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWhenAMemoryLeakOccurs.php
@@ -13,12 +13,12 @@ class WorkerGuaranteedToExitWhenAMemoryLeakOccurs extends BaseAcceptanceTestCase
*
* @dataProvider provideMemoryConsumptions
*/
- public function testWorkerKillItselfAfterAMemoryLeakButNotAfterABigMemoryConsumptionWithoutLeak($withMemoryLeak, $howManyItems, $memoryLimit, $expectedWorkerAlive)
+ public function testWorkerKillItselfAfterAMemoryLeakButNotAfterABigMemoryConsumptionWithoutLeak($withMemoryLeak, $howManyItems, $memoryLimit, $expectedWorkerAlive): void
{
- (new ConsumingMemoryCommand([
+ new ConsumingMemoryCommand([
'withMemoryLeak' => $withMemoryLeak,
'howManyItems' => $howManyItems,
- ]))
+ ])
->asJobOf($this->recruiter)
->inBackground()
->execute()
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
index 3d11950e..5070e67b 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
@@ -9,9 +9,9 @@ class WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest extends BaseAcc
/**
* @group acceptance
*/
- public function testInCaseOfExceptionTheExitCodeOfWorkerProcessIsNotZero()
+ public function testInCaseOfExceptionTheExitCodeOfWorkerProcessIsNotZero(): void
{
- (new ThrowsFatalError())
+ new ThrowsFatalError()
->asJobOf($this->recruiter)
->inBackground()
->execute()
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
index 83996c13..8e6c93fe 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToRetireAfterDeathTest.php
@@ -7,7 +7,7 @@ class WorkerGuaranteedToRetireAfterDeathTest extends BaseAcceptanceTestCase
/**
* @group acceptance
*/
- public function testRetireAfterAskedToStop()
+ public function testRetireAfterAskedToStop(): void
{
$numberOfWorkersBefore = $this->numberOfWorkers();
$processAndPipes = $this->startWorker();
diff --git a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
index cb1949d0..0c27dd63 100644
--- a/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
+++ b/spec/Recruiter/Acceptance/WorkerRepositoryTest.php
@@ -8,6 +8,7 @@ class WorkerRepositoryTest extends BaseAcceptanceTestCase
{
private Repository $repository;
+ #[\Override]
protected function setUp(): void
{
parent::setUp();
@@ -20,7 +21,7 @@ protected function setUp(): void
/**
* @group acceptance
*/
- public function testRetireWorkerWithPid()
+ public function testRetireWorkerWithPid(): void
{
$this->givenWorkerWithPid(10);
$this->assertEquals(1, $this->numberOfWorkers());
diff --git a/spec/Recruiter/CleanerTest.php b/spec/Recruiter/CleanerTest.php
index 0c8edb7f..8ae984a4 100644
--- a/spec/Recruiter/CleanerTest.php
+++ b/spec/Recruiter/CleanerTest.php
@@ -38,12 +38,12 @@ protected function tearDown(): void
T\clock()->start();
}
- public function testShouldCreateCleaner()
+ public function testShouldCreateCleaner(): void
{
- $this->assertInstanceOf('Recruiter\Cleaner', $this->cleaner);
+ $this->assertInstanceOf(Cleaner::class, $this->cleaner);
}
- public function testDelegatesTheCleanupOfArchivedJobsToTheJobsRepository()
+ public function testDelegatesTheCleanupOfArchivedJobsToTheJobsRepository(): void
{
$expectedUpperLimit = $this->now->before($this->interval);
diff --git a/spec/Recruiter/ExampleTest.php b/spec/Recruiter/ExampleTest.php
index 9b9b279f..9b4eecf5 100644
--- a/spec/Recruiter/ExampleTest.php
+++ b/spec/Recruiter/ExampleTest.php
@@ -6,7 +6,7 @@
class ExampleTest extends TestCase
{
- public function testMustPass()
+ public function testMustPass(): void
{
$this->assertTrue(true);
}
diff --git a/spec/Recruiter/FactoryTest.php b/spec/Recruiter/FactoryTest.php
index 3128cdc4..9f7fa61d 100644
--- a/spec/Recruiter/FactoryTest.php
+++ b/spec/Recruiter/FactoryTest.php
@@ -17,21 +17,21 @@ protected function setUp(): void
$this->mongoURI = MongoURI::fromEnvironment();
}
- public function testShouldCreateAMongoDatabaseConnection()
+ public function testShouldCreateAMongoDatabaseConnection(): void
{
$this->assertInstanceOf(
- 'MongoDB\Database',
+ Database::class,
$this->creationOfDefaultMongoDb(),
);
}
- public function testWriteConcernIsMajorityByDefault()
+ public function testWriteConcernIsMajorityByDefault(): void
{
$mongoDb = $this->creationOfDefaultMongoDb();
$this->assertEquals('majority', $mongoDb->getWriteConcern()->getW());
}
- public function testShouldOverwriteTheWriteConcernPassedInTheOptions()
+ public function testShouldOverwriteTheWriteConcernPassedInTheOptions(): void
{
$mongoDb = $this->factory->getMongoDb(
$this->mongoURI,
diff --git a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
index a89b6c6c..daceaafb 100644
--- a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
+++ b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
@@ -52,11 +52,9 @@ public function testFinalizableFailureMethodsAreCalledWhenJobFails(): void
$this->assertSame($exception, $calls[2][1]);
}
- public function testFinalizableSuccessfullMethodsAreCalledWhenJobIsDone()
+ public function testFinalizableSuccessfullMethodsAreCalledWhenJobIsDone(): void
{
- $workable = new FinalizableWorkable(function () {
- return true;
- }, $this->listener);
+ $workable = new FinalizableWorkable(fn () => true, $this->listener);
$job = Job::around($workable, $this->repository);
$job->execute($this->dispatcher);
@@ -85,38 +83,35 @@ class FinalizableWorkable implements Workable, Finalizable
private $whatToDo;
- private $listener;
-
- public function __construct(callable $whatToDo, $listener)
+ public function __construct(callable $whatToDo, private $listener)
{
$this->parameters = [];
- $this->listener = $listener;
$this->whatToDo = $whatToDo;
}
- public function execute()
+ public function execute(): mixed
{
$whatToDo = $this->whatToDo;
return $whatToDo();
}
- public function afterSuccess()
+ public function afterSuccess(): void
{
$this->listener->methodWasCalled(__FUNCTION__);
}
- public function afterFailure(\Exception $e)
+ public function afterFailure(\Exception $e): void
{
$this->listener->methodWasCalled(__FUNCTION__, $e);
}
- public function afterLastFailure(\Exception $e)
+ public function afterLastFailure(\Exception $e): void
{
$this->listener->methodWasCalled(__FUNCTION__, $e);
}
- public function finalize(?\Exception $e = null)
+ public function finalize(?\Exception $e = null): void
{
$this->listener->methodWasCalled(__FUNCTION__, $e);
}
diff --git a/spec/Recruiter/Infrastructure/Memory/MemoryLimitTest.php b/spec/Recruiter/Infrastructure/Memory/MemoryLimitTest.php
index 75507e1d..52012ec7 100644
--- a/spec/Recruiter/Infrastructure/Memory/MemoryLimitTest.php
+++ b/spec/Recruiter/Infrastructure/Memory/MemoryLimitTest.php
@@ -8,7 +8,7 @@
class MemoryLimitTest extends TestCase
{
- public function testThrowsAnExceptionWhenMemoryLimitIsExceeded()
+ public function testThrowsAnExceptionWhenMemoryLimitIsExceeded(): void
{
$this->expectException(MemoryLimitExceededException::class);
$memoryLimit = new MemoryLimit(1);
diff --git a/spec/Recruiter/Job/EventTest.php b/spec/Recruiter/Job/EventTest.php
index 4feb8e8b..33e5cb62 100644
--- a/spec/Recruiter/Job/EventTest.php
+++ b/spec/Recruiter/Job/EventTest.php
@@ -6,7 +6,7 @@
class EventTest extends TestCase
{
- public function testHasTagReturnsTrueWhenTheExportedJobContainsTheTag()
+ public function testHasTagReturnsTrueWhenTheExportedJobContainsTheTag(): void
{
$event = new Event([
'group' => 'generic',
@@ -18,7 +18,7 @@ public function testHasTagReturnsTrueWhenTheExportedJobContainsTheTag()
$this->assertTrue($event->hasTag('billing-notification'));
}
- public function testHasTagReturnsFalseWhenTheExportedJobDoesNotContainTheTag()
+ public function testHasTagReturnsFalseWhenTheExportedJobDoesNotContainTheTag(): void
{
$event = new Event([
'group' => 'generic',
@@ -30,7 +30,7 @@ public function testHasTagReturnsFalseWhenTheExportedJobDoesNotContainTheTag()
$this->assertFalse($event->hasTag('inexistant-tag'));
}
- public function testHasTagReturnsFalseWhenTheExportedJobDoesNotContainTags()
+ public function testHasTagReturnsFalseWhenTheExportedJobDoesNotContainTags(): void
{
$event = new Event([
]);
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 63c237ad..915e2685 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -43,7 +43,7 @@ protected function tearDown(): void
T\clock()->start();
}
- public function testCountsQueuedJobsAsOfNow()
+ public function testCountsQueuedJobsAsOfNow(): void
{
$this->aJobToSchedule()->inGroup('generic')->inBackground()->execute();
$this->aJobToSchedule()->inGroup('generic')->inBackground()->execute();
@@ -53,7 +53,7 @@ public function testCountsQueuedJobsAsOfNow()
$this->assertEquals(1, $this->repository->queued('fast-lane'));
}
- public function testCountsQueuedJobsWithCornerCaseTagging()
+ public function testCountsQueuedJobsWithCornerCaseTagging(): void
{
$this->aJobToSchedule()->inBackground()->execute();
$this->aJobToSchedule()->inGroup([])->inBackground()->execute();
@@ -63,7 +63,7 @@ public function testCountsQueuedJobsWithCornerCaseTagging()
$this->assertEquals(4, $this->repository->queued('generic'));
}
- public function testCountsQueudJobsWithScheduledAtGreatherThanASpecificDate()
+ public function testCountsQueudJobsWithScheduledAtGreatherThanASpecificDate(): void
{
$this->aJobToSchedule()->inBackground()->execute();
$time1 = $this->clock->now();
@@ -79,14 +79,14 @@ public function testCountsQueudJobsWithScheduledAtGreatherThanASpecificDate()
);
}
- public function testCountsPostponedJobs()
+ public function testCountsPostponedJobs(): void
{
$this->aJobToSchedule()->inBackground()->execute();
$this->aJobToSchedule()->scheduleIn(T\hour(24))->execute();
$this->assertEquals(1, $this->repository->postponed('generic'));
}
- public function testRecentHistory()
+ public function testRecentHistory(): void
{
$ed = $this->eventDispatcher;
$this->repository->archive($this->aJob()->beforeExecution($ed)->afterExecution(42, $ed));
@@ -109,7 +109,7 @@ public function testRecentHistory()
);
}
- public function testCountQueuedJobsGroupingByASpecificKeyword()
+ public function testCountQueuedJobsGroupingByASpecificKeyword(): void
{
$workable1 = $this->workableMock();
$workable2 = $this->workableMock();
@@ -142,7 +142,7 @@ public function testCountQueuedJobsGroupingByASpecificKeyword()
);
}
- public function testGetDelayedScheduledJobs()
+ public function testGetDelayedScheduledJobs(): void
{
$workable1 = $this->workableMockWithCustomParameters([
'job1' => 'delayed_and_unpicked',
@@ -168,7 +168,7 @@ public function testGetDelayedScheduledJobs()
$this->assertEquals(2, $jobsFounds);
}
- public function testCountDelayedScheduledJobs()
+ public function testCountDelayedScheduledJobs(): void
{
$this->aJobToSchedule($this->aJob())->inBackground()->execute();
$this->aJobToSchedule($this->aJob())->inBackground()->execute();
@@ -179,7 +179,7 @@ public function testCountDelayedScheduledJobs()
$this->assertEquals(2, $this->repository->countDelayedScheduledJobs($lowerLimit));
}
- public function testCountRecentJobsWithManyAttempts()
+ public function testCountRecentJobsWithManyAttempts(): void
{
$ed = $this->eventDispatcher;
$this->repository->archive($this->aJob()->beforeExecution($ed)->beforeExecution($ed)->afterExecution(42, $ed));
@@ -204,7 +204,7 @@ public function testCountRecentJobsWithManyAttempts()
$this->assertEquals(4, $this->repository->countRecentJobsWithManyAttempts($lowerLimit, $upperLimit));
}
- public function testGetRecentJobsWithManyAttempts()
+ public function testGetRecentJobsWithManyAttempts(): void
{
$ed = $this->eventDispatcher;
$workable1 = $this->workableMockWithCustomParameters([
@@ -251,7 +251,7 @@ public function testGetRecentJobsWithManyAttempts()
$this->assertEquals(4, $jobsFounds);
}
- public function testCountSlowRecentJobs()
+ public function testCountSlowRecentJobs(): void
{
$ed = $this->eventDispatcher;
$elapseTimeInSecondsBeforeJobsExecutionEnd = 6;
@@ -314,7 +314,7 @@ public function testCountSlowRecentJobs()
$this->assertEquals(4, $this->repository->countSlowRecentJobs($lowerLimit, $upperLimit));
}
- public function testGetSlowRecentJobs()
+ public function testGetSlowRecentJobs(): void
{
$ed = $this->eventDispatcher;
$elapseTimeInSecondsBeforeJobsExecutionEnd = 6;
@@ -397,7 +397,7 @@ public function testGetSlowRecentJobs()
$this->assertEquals(4, $jobsFounds);
}
- public function testCleanOldArchived()
+ public function testCleanOldArchived(): void
{
$ed = $this->eventDispatcher;
$this->repository->archive($this->aJob()->beforeExecution($ed)->afterExecution(42, $ed));
@@ -407,7 +407,7 @@ public function testCleanOldArchived()
$this->assertEquals(0, $this->repository->countArchived());
}
- public function testCleaningOfOldArchivedCanBeLimitedByTime()
+ public function testCleaningOfOldArchivedCanBeLimitedByTime(): void
{
$ed = $this->eventDispatcher;
$this->repository->archive($this->aJob()->beforeExecution($ed)->afterExecution(42, $ed));
@@ -490,7 +490,7 @@ private function jobMockWithAttemptsAndCustomParameters(
'ended_at' => T\MongoDate::from($endedAt),
],
'retry_policy' => [
- 'class' => 'Recruiter\RetryPolicy\DoNotDoItAgain',
+ 'class' => \Recruiter\RetryPolicy\DoNotDoItAgain::class,
'parameters' => [],
],
];
diff --git a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
index c96374ab..6c8970f8 100644
--- a/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
+++ b/spec/Recruiter/JobCallCustomMethodOnWorkableTest.php
@@ -30,20 +30,20 @@ protected function setUp(): void
$this->job = Job::around($this->workable, $this->repository);
}
- public function testConfigureMethodToCallOnWorkable()
+ public function testConfigureMethodToCallOnWorkable(): void
{
$this->workable->expects($this->once())->method('send');
$this->job->methodToCallOnWorkable('send');
$this->job->execute($this->createMock(EventDispatcherInterface::class));
}
- public function testRaiseExceptionWhenConfigureMethodToCallOnWorkableThatDoNotExists()
+ public function testRaiseExceptionWhenConfigureMethodToCallOnWorkableThatDoNotExists(): void
{
$this->expectException(\Exception::class);
$this->job->methodToCallOnWorkable('methodThatDoNotExists');
}
- public function testCustomMethodIsSaved()
+ public function testCustomMethodIsSaved(): void
{
$this->job->methodToCallOnWorkable('send');
$jobExportedToDocument = $this->job->export();
@@ -52,7 +52,7 @@ public function testCustomMethodIsSaved()
$this->assertEquals('send', $jobExportedToDocument['workable']['method']);
}
- public function testCustomMethodIsConservedAfterImport()
+ public function testCustomMethodIsConservedAfterImport(): void
{
$workable = new DummyWorkableWithSendCustomMethod();
$job = Job::around($workable, $this->repository);
diff --git a/spec/Recruiter/JobSendEventsToWorkableTest.php b/spec/Recruiter/JobSendEventsToWorkableTest.php
index 8bceaed7..e2bc698b 100644
--- a/spec/Recruiter/JobSendEventsToWorkableTest.php
+++ b/spec/Recruiter/JobSendEventsToWorkableTest.php
@@ -25,7 +25,7 @@ protected function setUp(): void
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
}
- public function testTakeRetryPolicyFromRetriableInstance()
+ public function testTakeRetryPolicyFromRetriableInstance(): void
{
$listener = new EventListenerSpy();
$workable = new WorkableThatIsAlsoAnEventListener($listener);
@@ -50,12 +50,12 @@ public function __construct(private readonly EventListener $listener)
$this->parameters = [];
}
- public function onEvent($channel, Event $ev)
+ public function onEvent($channel, Event $ev): void
{
- return $this->listener->onEvent($channel, $ev);
+ $this->listener->onEvent($channel, $ev);
}
- public function execute()
+ public function execute(): never
{
throw new \Exception();
}
diff --git a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
index 5385ce19..cd056f79 100644
--- a/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
+++ b/spec/Recruiter/JobTakeRetryPolicyFromRetriableWorkableTest.php
@@ -28,7 +28,7 @@ protected function setUp(): void
/**
* @throws Exception
*/
- public function testTakeRetryPolicyFromRetriableInstance()
+ public function testTakeRetryPolicyFromRetriableInstance(): void
{
$retryPolicy = $this->createMock(BaseRetryPolicy::class);
$retryPolicy->expects($this->once())->method('schedule');
@@ -54,7 +54,7 @@ public function retryWithPolicy(): RetryPolicy
return $this->retryWithPolicy;
}
- public function execute()
+ public function execute(): never
{
throw new \Exception();
}
diff --git a/spec/Recruiter/JobTest.php b/spec/Recruiter/JobTest.php
index 261f7575..09f3cc8d 100644
--- a/spec/Recruiter/JobTest.php
+++ b/spec/Recruiter/JobTest.php
@@ -22,7 +22,7 @@ protected function setUp(): void
;
}
- public function testRetryStatisticsOnFirstExecution()
+ public function testRetryStatisticsOnFirstExecution(): void
{
$job = Job::around(new AlwaysFail(), $this->repository);
$retryStatistics = $job->retryStatistics();
@@ -38,7 +38,7 @@ public function testRetryStatisticsOnFirstExecution()
/**
* @depends testRetryStatisticsOnFirstExecution
*/
- public function testRetryStatisticsOnSubsequentExecutions()
+ public function testRetryStatisticsOnSubsequentExecutions(): void
{
$job = Job::around(new AlwaysFail(), $this->repository);
// maybe make the argument optional
@@ -58,7 +58,7 @@ public function testRetryStatisticsOnSubsequentExecutions()
$this->assertMatchesRegularExpression('/.*AlwaysFail->execute.*/', $lastExecution['trace']);
}
- public function testArrayAsGroupIsNotAllowed()
+ public function testArrayAsGroupIsNotAllowed(): void
{
$this->expectException(\RuntimeException::class);
$memoryLimit = new MemoryLimit(1);
diff --git a/spec/Recruiter/JobToBePassedRetryStatisticsTest.php b/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
index 4f98057b..ec72fd4f 100644
--- a/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
+++ b/spec/Recruiter/JobToBePassedRetryStatisticsTest.php
@@ -25,7 +25,7 @@ protected function setUp(): void
/**
* @throws Exception
*/
- public function testTakeRetryPolicyFromRetriableInstance()
+ public function testTakeRetryPolicyFromRetriableInstance(): void
{
$workable = new WorkableThatUsesRetryStatistics();
diff --git a/spec/Recruiter/JobToScheduleTest.php b/spec/Recruiter/JobToScheduleTest.php
index 27b9496a..ce35099b 100644
--- a/spec/Recruiter/JobToScheduleTest.php
+++ b/spec/Recruiter/JobToScheduleTest.php
@@ -4,7 +4,6 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Timeless as T;
class JobToScheduleTest extends TestCase
@@ -27,7 +26,7 @@ protected function tearDown(): void
$this->clock->start();
}
- public function testInBackgroundShouldScheduleJobNow()
+ public function testInBackgroundShouldScheduleJobNow(): void
{
$this->job
->expects($this->once())
@@ -37,13 +36,13 @@ public function testInBackgroundShouldScheduleJobNow()
)
;
- (new JobToSchedule($this->job))
+ new JobToSchedule($this->job)
->inBackground()
->execute()
;
}
- public function testScheduledInShouldScheduleInCertainAmountOfTime()
+ public function testScheduledInShouldScheduleInCertainAmountOfTime(): void
{
$amountOfTime = T\minutes(10);
$this->job
@@ -54,13 +53,13 @@ public function testScheduledInShouldScheduleInCertainAmountOfTime()
)
;
- (new JobToSchedule($this->job))
+ new JobToSchedule($this->job)
->scheduleIn($amountOfTime)
->execute()
;
}
- public function testConfigureRetryPolicy()
+ public function testConfigureRetryPolicy(): void
{
$doNotDoItAgain = new RetryPolicy\DoNotDoItAgain();
@@ -70,29 +69,29 @@ public function testConfigureRetryPolicy()
->with($doNotDoItAgain)
;
- (new JobToSchedule($this->job))
+ new JobToSchedule($this->job)
->inBackground()
->retryWithPolicy($doNotDoItAgain)
->execute()
;
}
- public function tesShortcutToConfigureJobToNotBeRetried()
+ public function tesShortcutToConfigureJobToNotBeRetried(): void
{
$this->job
->expects($this->once())
->method('retryWithPolicy')
- ->with($this->isInstanceOf('Recruiter\RetryPolicy\DoNotDoItAgain'))
+ ->with($this->isInstanceOf(RetryPolicy\DoNotDoItAgain::class))
;
- (new JobToSchedule($this->job))
+ new JobToSchedule($this->job)
->inBackground()
->doNotRetry()
->execute()
;
}
- public function testShouldNotExecuteJobWhenScheduled()
+ public function testShouldNotExecuteJobWhenScheduled(): void
{
$this->job
->expects($this->once())
@@ -104,13 +103,13 @@ public function testShouldNotExecuteJobWhenScheduled()
->method('execute')
;
- (new JobToSchedule($this->job))
+ new JobToSchedule($this->job)
->inBackground()
->execute()
;
}
- public function testShouldExecuteJobWhenNotScheduled()
+ public function testShouldExecuteJobWhenNotScheduled(): void
{
$this->job
->expects($this->never())
@@ -122,14 +121,10 @@ public function testShouldExecuteJobWhenNotScheduled()
->method('execute')
;
- (new JobToSchedule($this->job))
- ->execute(
- $this->createMock(EventDispatcherInterface::class),
- )
- ;
+ new JobToSchedule($this->job)->execute();
}
- public function testConfigureMethodToCallOnWorkableInJob()
+ public function testConfigureMethodToCallOnWorkableInJob(): void
{
$this->job
->expects($this->once())
@@ -137,12 +132,12 @@ public function testConfigureMethodToCallOnWorkableInJob()
->with('send')
;
- (new JobToSchedule($this->job))
+ new JobToSchedule($this->job)
->send()
;
}
- public function testReturnsJobId()
+ public function testReturnsJobId(): void
{
$this->job
->expects($this->any())
@@ -152,10 +147,7 @@ public function testReturnsJobId()
$this->assertEquals(
'42',
- (new JobToSchedule($this->job))
- ->execute(
- $this->createMock(EventDispatcherInterface::class),
- ),
+ new JobToSchedule($this->job)->execute(),
);
}
}
diff --git a/spec/Recruiter/PickAvailableWorkersTest.php b/spec/Recruiter/PickAvailableWorkersTest.php
index 13c96ea9..2170aa23 100644
--- a/spec/Recruiter/PickAvailableWorkersTest.php
+++ b/spec/Recruiter/PickAvailableWorkersTest.php
@@ -25,7 +25,7 @@ protected function setUp(): void
$this->workersPerUnit = 42;
}
- public function testNoWorkersAreFound()
+ public function testNoWorkersAreFound(): void
{
$this->withNoAvailableWorkers();
@@ -46,7 +46,7 @@ public function testFewWorkersWithNoSpecificSkill(): void
$this->assertCount(3, $workers);
}
- public function testFewWorkersWithSameSkill()
+ public function testFewWorkersWithSameSkill(): void
{
$callbackHasBeenCalled = false;
$this->withAvailableWorkers(['send-emails' => 3]);
@@ -58,7 +58,7 @@ public function testFewWorkersWithSameSkill()
$this->assertEquals(3, count($workers));
}
- public function testFewWorkersWithSomeDifferentSkills()
+ public function testFewWorkersWithSomeDifferentSkills(): void
{
$this->withAvailableWorkers(['send-emails' => 3, 'count-transactions' => 3]);
$picked = Worker::pickAvailableWorkers($this->repository, $this->workersPerUnit);
@@ -74,7 +74,7 @@ public function testFewWorkersWithSomeDifferentSkills()
$this->assertEquals(6, $totalWorkersGiven);
}
- public function testMoreWorkersThanAllowedPerUnit()
+ public function testMoreWorkersThanAllowedPerUnit(): void
{
$this->withAvailableWorkers(['send-emails' => $this->workersPerUnit + 10]);
diff --git a/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php b/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
index 5c6e9e52..d9f3f966 100644
--- a/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
+++ b/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
@@ -8,7 +8,7 @@
class ExponentialBackoffTest extends TestCase
{
- public function testOnTheFirstFailureUsesTheSpecifiedInterval()
+ public function testOnTheFirstFailureUsesTheSpecifiedInterval(): void
{
$job = $this->jobExecutedFor(1);
$retryPolicy = new ExponentialBackoff(100, T\seconds(5));
@@ -20,7 +20,7 @@ public function testOnTheFirstFailureUsesTheSpecifiedInterval()
$retryPolicy->schedule($job);
}
- public function testAfterEachFailureDoublesTheAmountOfTimeToWaitBetweenRetries()
+ public function testAfterEachFailureDoublesTheAmountOfTimeToWaitBetweenRetries(): void
{
$job = $this->jobExecutedFor(2);
$retryPolicy = new ExponentialBackoff(100, T\seconds(5));
@@ -32,7 +32,7 @@ public function testAfterEachFailureDoublesTheAmountOfTimeToWaitBetweenRetries()
$retryPolicy->schedule($job);
}
- public function testAfterTooManyFailuresGivesUp()
+ public function testAfterTooManyFailuresGivesUp(): void
{
$job = $this->jobExecutedFor(101);
$retryPolicy = new ExponentialBackoff(100, T\seconds(5));
@@ -44,7 +44,7 @@ public function testAfterTooManyFailuresGivesUp()
$retryPolicy->schedule($job);
}
- public function testCanBeCreatedByTargetingAMaximumInterval()
+ public function testCanBeCreatedByTargetingAMaximumInterval(): void
{
$this->assertEquals(
ExponentialBackoff::forAnInterval(1025, T\seconds(1)),
diff --git a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
index 553a26a6..750063dc 100644
--- a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
+++ b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
@@ -19,10 +19,10 @@ protected function setUp(): void
$this->filteredRetryPolicy = $this->createMock(RetryPolicy::class);
}
- public function testCallScheduleOnRetriableException()
+ public function testCallScheduleOnRetriableException(): void
{
$exception = $this->createMock(\Exception::class);
- $classOfException = get_class($exception);
+ $classOfException = $exception::class;
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
$this->filteredRetryPolicy
@@ -33,10 +33,10 @@ public function testCallScheduleOnRetriableException()
$filter->schedule($this->jobFailedWithException($exception));
}
- public function testDoNotCallScheduleOnNonRetriableException()
+ public function testDoNotCallScheduleOnNonRetriableException(): void
{
$exception = $this->createMock(\Exception::class);
- $classOfException = get_class($exception);
+ $classOfException = $exception::class;
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
$this->filteredRetryPolicy
@@ -47,10 +47,10 @@ public function testDoNotCallScheduleOnNonRetriableException()
$filter->schedule($this->jobFailedWithException(new \Exception('Test')));
}
- public function testWhenExceptionIsNotRetriableThenArchiveTheJob()
+ public function testWhenExceptionIsNotRetriableThenArchiveTheJob(): void
{
$exception = $this->createMock(\Exception::class);
- $classOfException = get_class($exception);
+ $classOfException = $exception::class;
$filter = new RetriableExceptionFilter($this->filteredRetryPolicy, [$classOfException]);
$job = $this->jobFailedWithException(new \Exception('Test'));
@@ -62,7 +62,7 @@ public function testWhenExceptionIsNotRetriableThenArchiveTheJob()
$filter->schedule($job);
}
- public function testAllExceptionsAreRetriableByDefault()
+ public function testAllExceptionsAreRetriableByDefault(): void
{
$this->filteredRetryPolicy
->expects($this->once())
@@ -73,7 +73,7 @@ public function testAllExceptionsAreRetriableByDefault()
$filter->schedule($this->jobFailedWithException(new \Exception('Test')));
}
- public function testJobFailedWithSomethingThatIsNotAnException()
+ public function testJobFailedWithSomethingThatIsNotAnException(): void
{
$jobAfterFailure = $this->jobFailedWithException(null);
$jobAfterFailure
@@ -85,7 +85,7 @@ public function testJobFailedWithSomethingThatIsNotAnException()
$filter->schedule($jobAfterFailure);
}
- public function testExportFilteredRetryPolicy()
+ public function testExportFilteredRetryPolicy(): void
{
$this->filteredRetryPolicy
->expects($this->once())
@@ -99,7 +99,7 @@ public function testExportFilteredRetryPolicy()
[
'retriable_exceptions' => ['Exception'],
'filtered_retry_policy' => [
- 'class' => get_class($this->filteredRetryPolicy),
+ 'class' => $this->filteredRetryPolicy::class,
'parameters' => ['key' => 'value'],
],
],
@@ -107,7 +107,7 @@ public function testExportFilteredRetryPolicy()
);
}
- public function testImportRetryPolicy()
+ public function testImportRetryPolicy(): void
{
$filteredRetryPolicy = new DoNotDoItAgain();
$filter = new RetriableExceptionFilter($filteredRetryPolicy);
@@ -119,7 +119,7 @@ public function testImportRetryPolicy()
$this->assertEquals($exported, $filter->export());
}
- public function testRetriableExceptionsThatAreNotExceptions()
+ public function testRetriableExceptionsThatAreNotExceptions(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage("Only subclasses of Exception can be retriable exceptions, 'StdClass' is not");
diff --git a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
index 45c5904e..515a6e3f 100644
--- a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
+++ b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
@@ -9,7 +9,7 @@
class SelectByExceptionTest extends TestCase
{
- public function testCanBeBuilt()
+ public function testCanBeBuilt(): void
{
$retryPolicy = SelectByException::create()
->when(\InvalidArgumentException::class)->then(new DoNotDoItAgain())
@@ -20,7 +20,7 @@ public function testCanBeBuilt()
$this->assertInstanceOf(RetryPolicy::class, $retryPolicy);
}
- public function testCanBeExportedAndImported()
+ public function testCanBeExportedAndImported(): void
{
$retryPolicy = SelectByException::create()
->when(\InvalidArgumentException::class)->then(new DoNotDoItAgain())
@@ -35,11 +35,11 @@ public function testCanBeExportedAndImported()
$this->assertEquals($retryPolicyExported, $retryPolicyImported->export());
}
- public function testSelectByException()
+ public function testSelectByException(): void
{
$exception = new \InvalidArgumentException('something');
$retryPolicy = new SelectByException([
- new RetriableException(get_class($exception), RetryForever::afterSeconds(10)),
+ new RetriableException($exception::class, RetryForever::afterSeconds(10)),
]);
$job = $this->jobFailedWith($exception);
@@ -51,7 +51,7 @@ public function testSelectByException()
$retryPolicy->schedule($job);
}
- public function testDefaultDoNotSchedule()
+ public function testDefaultDoNotSchedule(): void
{
$exception = new \Exception('something');
$retryPolicy = new SelectByException([
diff --git a/spec/Recruiter/RetryPolicy/TimeTableTest.php b/spec/Recruiter/RetryPolicy/TimeTableTest.php
index a4bd304a..4110e6a9 100644
--- a/spec/Recruiter/RetryPolicy/TimeTableTest.php
+++ b/spec/Recruiter/RetryPolicy/TimeTableTest.php
@@ -20,7 +20,7 @@ protected function setUp(): void
]);
}
- public function testShouldRescheduleInOneMinuteWhenWasCreatedLessThanFiveMinutesAgo()
+ public function testShouldRescheduleInOneMinuteWhenWasCreatedLessThanFiveMinutesAgo(): void
{
$expectedToBeScheduledAt = T\minute(1)->fromNow()->toSecondPrecision();
$wasCreatedAt = T\seconds(10)->ago();
@@ -32,7 +32,7 @@ public function testShouldRescheduleInOneMinuteWhenWasCreatedLessThanFiveMinutes
$this->scheduler->schedule($job);
}
- public function testShouldRescheduleInFiveMinutesWhenWasCreatedLessThanOneHourAgo()
+ public function testShouldRescheduleInFiveMinutesWhenWasCreatedLessThanOneHourAgo(): void
{
$expectedToBeScheduledAt = T\minutes(5)->fromNow()->toSecondPrecision();
$wasCreatedAt = T\minutes(30)->ago();
@@ -44,7 +44,7 @@ public function testShouldRescheduleInFiveMinutesWhenWasCreatedLessThanOneHourAg
$this->scheduler->schedule($job);
}
- public function testShouldRescheduleInFiveMinutesWhenWasCreatedLessThan24HoursAgo()
+ public function testShouldRescheduleInFiveMinutesWhenWasCreatedLessThan24HoursAgo(): void
{
$expectedToBeScheduledAt = T\hour(1)->fromNow()->toSecondPrecision();
$wasCreatedAt = T\hours(3)->ago();
@@ -56,14 +56,14 @@ public function testShouldRescheduleInFiveMinutesWhenWasCreatedLessThan24HoursAg
$this->scheduler->schedule($job);
}
- public function testShouldNotBeRescheduledWhenWasCreatedMoreThan24HoursAgo()
+ public function testShouldNotBeRescheduledWhenWasCreatedMoreThan24HoursAgo(): void
{
$job = $this->jobThatWasCreated('2 days ago');
$job->expects($this->never())->method('scheduleAt');
$this->scheduler->schedule($job);
}
- public function testIsLastRetryReturnTrueIfJobWasCreatedMoreThanLastTimeSpen()
+ public function testIsLastRetryReturnTrueIfJobWasCreatedMoreThanLastTimeSpen(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->any())
@@ -78,7 +78,7 @@ public function testIsLastRetryReturnTrueIfJobWasCreatedMoreThanLastTimeSpen()
$this->assertTrue($tt->isLastRetry($job));
}
- public function testIsLastRetryReturnFalseIfJobWasCreatedLessThanLastTimeSpen()
+ public function testIsLastRetryReturnFalseIfJobWasCreatedLessThanLastTimeSpen(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->any())
@@ -93,19 +93,19 @@ public function testIsLastRetryReturnFalseIfJobWasCreatedLessThanLastTimeSpen()
$this->assertFalse($tt->isLastRetry($job));
}
- public function testInvalidTimeTableBecauseTimeWindow()
+ public function testInvalidTimeTableBecauseTimeWindow(): void
{
$this->expectException(\Exception::class);
$tt = new TimeTable(['1 minute' => '1 second']);
}
- public function testInvalidTimeTableBecauseRescheduleTime()
+ public function testInvalidTimeTableBecauseRescheduleTime(): void
{
$this->expectException(\Exception::class);
$tt = new TimeTable(['1 minute ago' => '1 second ago']);
}
- public function testInvalidTimeTableBecauseRescheduleTimeIsGreaterThanTimeWindow()
+ public function testInvalidTimeTableBecauseRescheduleTimeIsGreaterThanTimeWindow(): void
{
$this->expectException(\Exception::class);
$tt = new TimeTable(['1 minute ago' => '2 minutes']);
@@ -120,13 +120,13 @@ private function givenJobThat(T\Moment $wasCreatedAt)
;
$job->expects($this->any())
->method('createdAt')
- ->will($this->returnValue($wasCreatedAt))
+ ->willReturn($wasCreatedAt)
;
return $job;
}
- private function jobThatWasCreated($relativeTime)
+ private function jobThatWasCreated(string $relativeTime): JobAfterFailure
{
$wasCreatedAt = T\Moment::fromTimestamp(strtotime($relativeTime));
$job = $this->getMockBuilder(JobAfterFailure::class)
@@ -136,7 +136,7 @@ private function jobThatWasCreated($relativeTime)
;
$job->expects($this->any())
->method('createdAt')
- ->will($this->returnValue($wasCreatedAt))
+ ->willReturn($wasCreatedAt)
;
return $job;
diff --git a/spec/Recruiter/SchedulePolicy/CronTest.php b/spec/Recruiter/SchedulePolicy/CronTest.php
index bac7a8cf..3d6804c6 100644
--- a/spec/Recruiter/SchedulePolicy/CronTest.php
+++ b/spec/Recruiter/SchedulePolicy/CronTest.php
@@ -10,7 +10,7 @@ class CronTest extends TestCase
/**
* @dataProvider cronExpressions
*/
- public function testCronCanBeExportedAndImportedWithoutDataLoss(string $cronExpression, string $expectedDate)
+ public function testCronCanBeExportedAndImportedWithoutDataLoss(string $cronExpression, string $expectedDate): void
{
$cron = new Cron($cronExpression, \DateTime::createFromFormat('Y-m-d H:i:s', '2019-01-15 15:00:00'));
$cron = Cron::import($cron->export());
diff --git a/spec/Recruiter/TaggableWorkableTest.php b/spec/Recruiter/TaggableWorkableTest.php
index c6ead3f8..65e96aa4 100644
--- a/spec/Recruiter/TaggableWorkableTest.php
+++ b/spec/Recruiter/TaggableWorkableTest.php
@@ -19,7 +19,7 @@ protected function setUp(): void
;
}
- public function testWorkableExportsTags()
+ public function testWorkableExportsTags(): void
{
$workable = new WorkableTaggable(['a', 'b']);
$job = Job::around($workable, $this->repository);
@@ -29,7 +29,7 @@ public function testWorkableExportsTags()
$this->assertEquals(['a', 'b'], $exported['tags']);
}
- public function testCanSetTagsOnJobs()
+ public function testCanSetTagsOnJobs(): void
{
$workable = new WorkableTaggable([]);
$job = Job::around($workable, $this->repository);
@@ -40,7 +40,7 @@ public function testCanSetTagsOnJobs()
$this->assertEquals(['c'], $exported['tags']);
}
- public function testTagsAreMergedTogether()
+ public function testTagsAreMergedTogether(): void
{
$workable = new WorkableTaggable(['a', 'b']);
$job = Job::around($workable, $this->repository);
@@ -51,7 +51,7 @@ public function testTagsAreMergedTogether()
$this->assertEquals(['a', 'b', 'c'], $exported['tags']);
}
- public function testTagsAreUnique()
+ public function testTagsAreUnique(): void
{
$workable = new WorkableTaggable(['c']);
$job = Job::around($workable, $this->repository);
@@ -62,7 +62,7 @@ public function testTagsAreUnique()
$this->assertEquals(['c'], $exported['tags']);
}
- public function testEmptyTagsAreNotExported()
+ public function testEmptyTagsAreNotExported(): void
{
$workable = new WorkableTaggable([]);
$job = Job::around($workable, $this->repository);
@@ -71,7 +71,7 @@ public function testEmptyTagsAreNotExported()
$this->assertArrayNotHasKey('tags', $exported);
}
- public function testTagsAreImported()
+ public function testTagsAreImported(): void
{
$workable = new WorkableTaggable(['a', 'b']);
$job = Job::around($workable, $this->repository);
@@ -96,14 +96,11 @@ class WorkableTaggable implements Workable, Taggable
{
use WorkableBehaviour;
- private $tags;
-
- public function __construct(array $tags)
+ public function __construct(private array $tags)
{
- $this->tags = $tags;
}
- public function taggedAs()
+ public function taggedAs(): array
{
return $this->tags;
}
diff --git a/spec/Recruiter/WaitStrategyTest.php b/spec/Recruiter/WaitStrategyTest.php
index 4ff7a53e..62b3578f 100644
--- a/spec/Recruiter/WaitStrategyTest.php
+++ b/spec/Recruiter/WaitStrategyTest.php
@@ -22,7 +22,7 @@ protected function setUp(): void
$this->timeToWaitAtMost = T\seconds(30);
}
- public function testStartsToWaitTheMinimumAmountOfTime()
+ public function testStartsToWaitTheMinimumAmountOfTime(): void
{
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
@@ -33,7 +33,7 @@ public function testStartsToWaitTheMinimumAmountOfTime()
$this->assertEquals($this->timeToWaitAtLeast, $this->waited);
}
- public function testBackingOffIncreasesTheIntervalExponentially()
+ public function testBackingOffIncreasesTheIntervalExponentially(): void
{
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
@@ -48,7 +48,7 @@ public function testBackingOffIncreasesTheIntervalExponentially()
$this->assertEquals($this->timeToWaitAtLeast->multiplyBy(4), $this->waited);
}
- public function testBackingOffCannotIncreaseTheIntervalOverAMaximum()
+ public function testBackingOffCannotIncreaseTheIntervalOverAMaximum(): void
{
$ws = new WaitStrategy(T\seconds(1), T\seconds(2), $this->howToWait);
$ws->backOff();
@@ -59,7 +59,7 @@ public function testBackingOffCannotIncreaseTheIntervalOverAMaximum()
$this->assertEquals(T\seconds(2), $this->waited);
}
- public function testGoingForwardLowersTheSleepingPeriod()
+ public function testGoingForwardLowersTheSleepingPeriod(): void
{
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
@@ -72,7 +72,7 @@ public function testGoingForwardLowersTheSleepingPeriod()
$this->assertEquals($this->timeToWaitAtLeast, $this->waited);
}
- public function testTheSleepingPeriodCanBeResetToTheMinimum()
+ public function testTheSleepingPeriodCanBeResetToTheMinimum(): void
{
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
@@ -88,7 +88,7 @@ public function testTheSleepingPeriodCanBeResetToTheMinimum()
$this->assertEquals($this->timeToWaitAtLeast, $this->waited);
}
- public function testGoingForwardCannotLowerTheIntervalBelowMinimum()
+ public function testGoingForwardCannotLowerTheIntervalBelowMinimum(): void
{
$ws = new WaitStrategy(
$this->timeToWaitAtLeast,
diff --git a/spec/Recruiter/Workable/FactoryMethodCommandTest.php b/spec/Recruiter/Workable/FactoryMethodCommandTest.php
index b7263e2d..05950dd4 100644
--- a/spec/Recruiter/Workable/FactoryMethodCommandTest.php
+++ b/spec/Recruiter/Workable/FactoryMethodCommandTest.php
@@ -6,7 +6,7 @@
class FactoryMethodCommandTest extends TestCase
{
- public function testExecutedACommandReachableFromAStaticFactoryMethod()
+ public function testExecutedACommandReachableFromAStaticFactoryMethod(): void
{
$workable = FactoryMethodCommand::from('Recruiter\Workable\DummyFactory::create')
->myObject()
@@ -15,7 +15,7 @@ public function testExecutedACommandReachableFromAStaticFactoryMethod()
$this->assertEquals('42', $workable->execute());
}
- public function testCanBeImportedAndExported()
+ public function testCanBeImportedAndExported(): void
{
$workable = FactoryMethodCommand::from('Recruiter\Workable\DummyFactory::create')
->myObject()
@@ -27,7 +27,7 @@ public function testCanBeImportedAndExported()
);
}
- public function testPassesRetryStatisticsAsAnAdditionalArgumentToTheLastMethodToCall()
+ public function testPassesRetryStatisticsAsAnAdditionalArgumentToTheLastMethodToCall(): void
{
$workable = FactoryMethodCommand::from('Recruiter\Workable\DummyFactory::create')
->myObject()
diff --git a/spec/Recruiter/Workable/ShellCommandTest.php b/spec/Recruiter/Workable/ShellCommandTest.php
index 2eba223f..a5cbc362 100644
--- a/spec/Recruiter/Workable/ShellCommandTest.php
+++ b/spec/Recruiter/Workable/ShellCommandTest.php
@@ -6,13 +6,13 @@
class ShellCommandTest extends TestCase
{
- public function testExecutesACommandOnTheShell()
+ public function testExecutesACommandOnTheShell(): void
{
$workable = ShellCommand::fromCommandLine('echo 42');
$this->assertEquals('42', $workable->execute());
}
- public function testCanBeImportedAndExported()
+ public function testCanBeImportedAndExported(): void
{
$workable = ShellCommand::fromCommandLine('echo 42');
$this->assertEquals(
diff --git a/spec/Recruiter/WorkablePersistenceTest.php b/spec/Recruiter/WorkablePersistenceTest.php
index ac8e3e71..283b528f 100644
--- a/spec/Recruiter/WorkablePersistenceTest.php
+++ b/spec/Recruiter/WorkablePersistenceTest.php
@@ -6,7 +6,7 @@
class WorkablePersistenceTest extends TestCase
{
- public function testCanBeExportedAndImported()
+ public function testCanBeExportedAndImported(): void
{
$job = new SomethingWorkable(['key' => 'value']);
$this->assertEquals(
diff --git a/spec/Recruiter/WorkerProcessTest.php b/spec/Recruiter/WorkerProcessTest.php
index bcd50437..07a036b6 100644
--- a/spec/Recruiter/WorkerProcessTest.php
+++ b/spec/Recruiter/WorkerProcessTest.php
@@ -23,19 +23,19 @@ protected function setUp(): void
;
}
- public function testIfNotAliveWhenIsNotAliveReturnsItself()
+ public function testIfNotAliveWhenIsNotAliveReturnsItself(): void
{
$process = $this->givenWorkerProcessDead();
$this->assertInstanceOf(Process::class, $process->ifDead());
}
- public function testIfNotAliveWhenIsAliveReturnsBlackHole()
+ public function testIfNotAliveWhenIsAliveReturnsBlackHole(): void
{
$process = $this->givenWorkerProcessAlive();
$this->assertInstanceOf(BlackHole::class, $process->ifDead());
}
- public function testRetireWorkerIfNotAlive()
+ public function testRetireWorkerIfNotAlive(): void
{
$this->repository
->expects($this->once())
@@ -47,7 +47,7 @@ public function testRetireWorkerIfNotAlive()
$process->cleanUp($this->repository);
}
- public function testDoNotRetireWorkerIfAlive()
+ public function testDoNotRetireWorkerIfAlive(): void
{
$this->repository
->expects($this->never())
diff --git a/spec/Sink/BlackHoleTest.php b/spec/Sink/BlackHoleTest.php
index 097ec792..2fa25654 100644
--- a/spec/Sink/BlackHoleTest.php
+++ b/spec/Sink/BlackHoleTest.php
@@ -6,61 +6,61 @@
class BlackHoleTest extends TestCase
{
- public function testMethodCall()
+ public function testMethodCall(): void
{
$instance = new BlackHole();
- $this->assertInstanceOf('Sink\BlackHole', $instance->whateverMethod());
+ $this->assertInstanceOf(BlackHole::class, $instance->whateverMethod());
}
- public function testGetter()
+ public function testGetter(): void
{
$instance = new BlackHole();
- $this->assertInstanceOf('Sink\BlackHole', $instance->whateverProperty);
+ $this->assertInstanceOf(BlackHole::class, $instance->whateverProperty);
}
- public function testSetterReturnsTheValue()
+ public function testSetterReturnsTheValue(): void
{
$instance = new BlackHole();
$this->assertEquals(42, $instance->whateverProperty = 42);
}
- public function testNothingIsSet()
+ public function testNothingIsSet(): void
{
$instance = new BlackHole();
$instance->whateverProperty = 42;
$this->assertFalse(isset($instance->whateverProperty));
}
- public function testToString()
+ public function testToString(): void
{
$instance = new BlackHole();
$this->assertEquals('', (string) $instance);
}
- public function testInvoke()
+ public function testInvoke(): void
{
$instance = new BlackHole();
- $this->assertInstanceOf('Sink\BlackHole', $instance());
+ $this->assertInstanceOf(BlackHole::class, $instance());
}
- public function testCallStatic()
+ public function testCallStatic(): void
{
$instance = BlackHole::whateverStaticMethod();
- $this->assertInstanceOf('Sink\BlackHole', $instance);
+ $this->assertInstanceOf(BlackHole::class, $instance);
}
- public function testIsIterableButItIsAlwaysEmpty()
+ public function testIsIterableButItIsAlwaysEmpty(): void
{
$instance = new BlackHole();
$this->assertEmpty(iterator_to_array($instance));
}
- public function testIsAccessibleAsAnArrayAlwaysGetItself()
+ public function testIsAccessibleAsAnArrayAlwaysGetItself(): void
{
$instance = new BlackHole();
- $this->assertInstanceOf('Sink\BlackHole', $instance[42]);
- $this->assertInstanceOf('Sink\BlackHole', $instance['aString']);
- $this->assertInstanceOf('Sink\BlackHole', $instance[[1, 2, 3]]);
+ $this->assertInstanceOf(BlackHole::class, $instance[42]);
+ $this->assertInstanceOf(BlackHole::class, $instance['aString']);
+ $this->assertInstanceOf(BlackHole::class, $instance[[1, 2, 3]]);
}
/* public function testIsAccessibleAsAnArrayExists() */
diff --git a/spec/Timeless/IntervalFormatTest.php b/spec/Timeless/IntervalFormatTest.php
index 5a697c11..208368bf 100644
--- a/spec/Timeless/IntervalFormatTest.php
+++ b/spec/Timeless/IntervalFormatTest.php
@@ -6,7 +6,7 @@
class IntervalFormatTest extends TestCase
{
- public function testFormatExtended()
+ public function testFormatExtended(): void
{
$this->assertEquals('4 milliseconds', milliseconds(4)->format('milliseconds'));
$this->assertEquals('1 second', milliseconds(1000)->format('seconds'));
@@ -19,7 +19,7 @@ public function testFormatExtended()
$this->assertEquals('1 year', months(12)->format('years'));
}
- public function testFormatShort()
+ public function testFormatShort(): void
{
$this->assertEquals('4ms', milliseconds(4)->format('ms'));
$this->assertEquals('1s', milliseconds(1000)->format('s'));
diff --git a/spec/Timeless/IntervalParseTest.php b/spec/Timeless/IntervalParseTest.php
index 8cc384f4..bbd276d1 100644
--- a/spec/Timeless/IntervalParseTest.php
+++ b/spec/Timeless/IntervalParseTest.php
@@ -6,7 +6,7 @@
class IntervalParseTest extends TestCase
{
- public function testParseExtendedFormat()
+ public function testParseExtendedFormat(): void
{
$this->assertEquals(milliseconds(4), Interval::parse('4 milliseconds'));
$this->assertEquals(milliseconds(4), Interval::parse('4milliseconds'));
@@ -65,7 +65,7 @@ public function testParseExtendedFormat()
$this->assertEquals(years(1), Interval::parse('1 year'));
}
- public function testParseShortFormat()
+ public function testParseShortFormat(): void
{
$this->assertEquals(milliseconds(4), Interval::parse('4 ms'));
$this->assertEquals(milliseconds(4), Interval::parse('4ms'));
@@ -85,21 +85,21 @@ public function testParseShortFormat()
$this->assertEquals(years(4), Interval::parse('4y'));
}
- public function testFromDateInterval()
+ public function testFromDateInterval(): void
{
$this->assertEquals(days(2), Interval::fromDateInterval(new \DateInterval('P2D')));
$this->assertEquals(minutes(10), Interval::fromDateInterval(new \DateInterval('PT10M')));
$this->assertEquals(days(2)->add(minutes(10)), Interval::fromDateInterval(new \DateInterval('P2DT10M')));
}
- public function testNumberAsIntervalFormat()
+ public function testNumberAsIntervalFormat(): void
{
$this->expectException(InvalidIntervalFormat::class);
$this->expectExceptionMessage("Maybe you mean '5 seconds' or something like that?");
Interval::parse(5);
}
- public function testBadString()
+ public function testBadString(): void
{
$this->expectException(InvalidIntervalFormat::class);
Interval::parse('whatever');
diff --git a/spec/Timeless/MongoDateTest.php b/spec/Timeless/MongoDateTest.php
index a7095a37..ad7bb26e 100644
--- a/spec/Timeless/MongoDateTest.php
+++ b/spec/Timeless/MongoDateTest.php
@@ -10,7 +10,7 @@ class MongoDateTest extends TestCase
{
use Eris\TestTrait;
- public function testConvertsBackAndForthMongoDatesWithoutLosingMillisecondPrecision()
+ public function testConvertsBackAndForthMongoDatesWithoutLosingMillisecondPrecision(): void
{
$this
->forAll(
diff --git a/src/Recruiter/Cleaner.php b/src/Recruiter/Cleaner.php
index e6ef6097..4b7a03c9 100644
--- a/src/Recruiter/Cleaner.php
+++ b/src/Recruiter/Cleaner.php
@@ -8,14 +8,8 @@
class Cleaner
{
- /**
- * @var Repository
- */
- private $repository;
-
- public function __construct(Repository $repository)
+ public function __construct(private readonly Repository $repository)
{
- $this->repository = $repository;
}
public function cleanArchived(Interval $gracePeriod)
diff --git a/src/Recruiter/Finalizable.php b/src/Recruiter/Finalizable.php
index 6804f06c..c7433dcc 100644
--- a/src/Recruiter/Finalizable.php
+++ b/src/Recruiter/Finalizable.php
@@ -6,11 +6,11 @@
interface Finalizable
{
- public function afterSuccess();
+ public function afterSuccess(): void;
- public function afterFailure(\Exception $e);
+ public function afterFailure(\Exception $e): void;
- public function afterLastFailure(\Exception $e);
+ public function afterLastFailure(\Exception $e): void;
- public function finalize(?\Exception $e = null);
+ public function finalize(?\Exception $e = null): void;
}
diff --git a/src/Recruiter/FinalizableBehaviour.php b/src/Recruiter/FinalizableBehaviour.php
index c50a10d7..ce5bcc18 100644
--- a/src/Recruiter/FinalizableBehaviour.php
+++ b/src/Recruiter/FinalizableBehaviour.php
@@ -6,19 +6,19 @@
trait FinalizableBehaviour
{
- public function afterSuccess()
+ public function afterSuccess(): void
{
}
- public function afterFailure(\Exception $e)
+ public function afterFailure(\Exception $e): void
{
}
- public function afterLastFailure(\Exception $e)
+ public function afterLastFailure(\Exception $e): void
{
}
- public function finalize(?\Exception $e = null)
+ public function finalize(?\Exception $e = null): void
{
}
}
diff --git a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
index e29aec32..94e5fb2c 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/AnalyticsCommand.php
@@ -87,8 +87,8 @@ private function calculateColumnsWidth(array $analytics): int
$maxColumns = max($maxColumns, count($analytic));
}
- // casual constants, found by try and error
- $terminalWidth = (new Terminal())->getWidth() - (($maxColumns + 2) * 2);
+ // casual constants, found by trial and error
+ $terminalWidth = new Terminal()->getWidth() - (($maxColumns + 2) * 2);
return intval(floor($terminalWidth / $maxColumns));
}
diff --git a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
index a81bd66a..29369c47 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
@@ -19,26 +19,14 @@
class RemoveSchedulerCommand extends Command
{
- /**
- * @var Factory
- */
- private $factory;
-
- /**
- * @var LoggerInterface
- */
- private $logger;
-
/**
* @var SchedulerRepository
*/
private $schedulerRepository;
- public function __construct(Factory $factory, LoggerInterface $logger)
+ public function __construct(private readonly Factory $factory, private readonly LoggerInterface $logger)
{
parent::__construct();
- $this->factory = $factory;
- $this->logger = $logger;
}
protected function configure()
diff --git a/src/Recruiter/Infrastructure/Command/CleanerCommand.php b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
index cbf85798..ee0ff3d3 100644
--- a/src/Recruiter/Infrastructure/Command/CleanerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/CleanerCommand.php
@@ -26,45 +26,14 @@
class CleanerCommand implements RobustCommand
{
- /**
- * @var Factory
- */
- private $factory;
-
- /**
- * @var Cleaner
- */
- private $cleaner;
-
- /**
- * @var LeadershipStrategy
- */
- private $leadershipStrategy;
-
- /**
- * @var WaitStrategy
- */
- private $waitStrategy;
-
- /**
- * @var MemoryLimit
- */
- private $memoryLimit;
-
- /**
- * @var Interval
- */
- private $gracePeriod;
-
- /**
- * @var LoggerInterface
- */
- private $logger;
-
- public function __construct($factory, LoggerInterface $logger)
+ private Cleaner $cleaner;
+ private LeadershipStrategy $leadershipStrategy;
+ private WaitStrategy $waitStrategy;
+ private MemoryLimit $memoryLimit;
+ private Interval $gracePeriod;
+
+ public function __construct(private readonly Factory $factory, private readonly LoggerInterface $logger)
{
- $this->factory = $factory;
- $this->logger = $logger;
}
public static function toRobustCommand(Factory $factory, LoggerInterface $logger): RobustCommandRunner
diff --git a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
index 67b907f5..287ab84c 100644
--- a/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
+++ b/src/Recruiter/Infrastructure/Command/RecruiterCommand.php
@@ -27,45 +27,14 @@
class RecruiterCommand implements RobustCommand, LeadershipEventsHandler
{
- /**
- * @var Factory
- */
- private $factory;
+ private Recruiter $recruiter;
+ private Interval $consideredDeadAfter;
+ private LeadershipStrategy $leadershipStrategy;
+ private WaitStrategy $waitStrategy;
+ private MemoryLimit $memoryLimit;
- /**
- * @var Recruiter
- */
- private $recruiter;
-
- /**
- * @var Interval
- */
- private $consideredDeadAfter;
-
- /**
- * @var LeadershipStrategy
- */
- private $leadershipStrategy;
-
- /**
- * @var WaitStrategy
- */
- private $waitStrategy;
-
- /**
- * @var MemoryLimit
- */
- private $memoryLimit;
-
- /**
- * @var LoggerInterface
- */
- private $logger;
-
- public function __construct($factory, LoggerInterface $logger)
+ public function __construct(private readonly Factory $factory, private readonly LoggerInterface $logger)
{
- $this->factory = $factory;
- $this->logger = $logger;
}
public static function toRobustCommand(Factory $factory, LoggerInterface $logger): RobustCommandRunner
@@ -83,7 +52,7 @@ public function execute(): bool
return count($assignment) > 0;
}
- private function rollbackLockedJobs()
+ private function rollbackLockedJobs(): void
{
$rollbackStartAt = microtime(true);
$rolledBack = $this->recruiter->rollbackLockedJobs();
@@ -133,7 +102,7 @@ private function scheduleRepeatableJobs(): void
));
}
- private function retireDeadWorkers()
+ private function retireDeadWorkers(): void
{
$unlockedJobs = $this->recruiter->retireDeadWorkers(
new \DateTimeImmutable(),
diff --git a/src/Recruiter/Infrastructure/Command/WorkerCommand.php b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
index d9c1331f..81927a4a 100644
--- a/src/Recruiter/Infrastructure/Command/WorkerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/WorkerCommand.php
@@ -26,11 +26,6 @@
class WorkerCommand implements RobustCommand
{
- /**
- * @var Factory
- */
- private $factory;
-
/**
* @var Worker
*/
@@ -47,14 +42,10 @@ class WorkerCommand implements RobustCommand
private $waitStrategy;
/**
- * @var LoggerInterface
+ * @param Factory $factory
*/
- private $logger;
-
- public function __construct($factory, LoggerInterface $logger)
+ public function __construct(private $factory, private readonly LoggerInterface $logger)
{
- $this->factory = $factory;
- $this->logger = $logger;
}
public static function toRobustCommand(Factory $factory, LoggerInterface $logger): RobustCommandRunner
diff --git a/src/Recruiter/Infrastructure/Filesystem/BootstrapFile.php b/src/Recruiter/Infrastructure/Filesystem/BootstrapFile.php
index 68cf7cab..860d6fb1 100644
--- a/src/Recruiter/Infrastructure/Filesystem/BootstrapFile.php
+++ b/src/Recruiter/Infrastructure/Filesystem/BootstrapFile.php
@@ -11,14 +11,9 @@
*/
class BootstrapFile
{
- /**
- * @var string
- */
- private $filePath;
-
- public function __construct(string $filePath)
+ public function __construct(private readonly string $filePath)
{
- $this->filePath = $this->validate($filePath);
+ $this->validate($filePath);
}
public static function fromFilePath(string $filePath): self
@@ -31,7 +26,7 @@ public function load(Recruiter $recruiter)
return require $this->filePath;
}
- private function validate($filePath): string
+ private function validate(string $filePath): void
{
if (!file_exists($filePath)) {
$this->throwBecauseFile($filePath, "doesn't exists");
@@ -40,11 +35,9 @@ private function validate($filePath): string
if (!is_readable($filePath)) {
$this->throwBecauseFile($filePath, 'is not readable');
}
-
- return $filePath;
}
- private function throwBecauseFile($filePath, $reason)
+ private function throwBecauseFile(string $filePath, string $reason): never
{
throw new \UnexpectedValueException(sprintf("Bootstrap file has an invalid value: file '%s' %s", $filePath, $reason));
}
diff --git a/src/Recruiter/Job.php b/src/Recruiter/Job.php
index 17122d13..b784650b 100644
--- a/src/Recruiter/Job.php
+++ b/src/Recruiter/Job.php
@@ -14,13 +14,7 @@
class Job
{
- private $status;
- private $workable;
- private $retryPolicy;
- private $repository;
- private $lastJobExecution;
-
- public static function around(Workable $workable, Repository $repository)
+ public static function around(Workable $workable, Repository $repository): self
{
return new self(
self::initialize(),
@@ -32,7 +26,7 @@ public static function around(Workable $workable, Repository $repository)
);
}
- public static function import($document, Repository $repository)
+ public static function import($document, Repository $repository): self
{
return new self(
$document,
@@ -43,13 +37,13 @@ public static function import($document, Repository $repository)
);
}
- public function __construct($status, Workable $workable, RetryPolicy $retryPolicy, JobExecution $lastJobExecution, Repository $repository)
- {
- $this->status = $status;
- $this->workable = $workable;
- $this->retryPolicy = $retryPolicy;
- $this->lastJobExecution = $lastJobExecution;
- $this->repository = $repository;
+ public function __construct(
+ private array $status,
+ private readonly Workable $workable,
+ private RetryPolicy $retryPolicy,
+ private JobExecution $lastJobExecution,
+ private readonly Repository $repository,
+ ) {
}
public function id()
@@ -57,7 +51,7 @@ public function id()
return $this->status['_id'];
}
- public function createdAt()
+ public function createdAt(): Moment
{
return T\MongoDate::toMoment($this->status['created_at']);
}
@@ -74,7 +68,10 @@ public function retryWithPolicy(RetryPolicy $retryPolicy)
return $this;
}
- public function taggedAs(array $tags)
+ /**
+ * @return $this
+ */
+ public function taggedAs(array $tags): static
{
if (!empty($tags)) {
$this->status['tags'] = $tags;
@@ -83,12 +80,15 @@ public function taggedAs(array $tags)
return $this;
}
- public function inGroup($group)
+ public function inGroup(array|string $group): static
{
if (is_array($group)) {
- throw new \RuntimeException('Group can be only single string, for other uses use `taggedAs` method.
- Received group: `' . var_export($group, true) . '`');
+ throw new \RuntimeException(
+ "Group can be only single string, for other uses use `taggedAs` method.
+ Received group: `" . var_export($group, true) . "`"
+ );
}
+
if (!empty($group)) {
$this->status['group'] = $group;
}
@@ -318,8 +318,7 @@ public static function pickReadyJobsForWorkers(MongoCollection $collection, $wor
['scheduled_at' => ['$lt' => T\MongoDate::now()],
'locked' => false,
'group' => $worksOn,
- ]
- ,
+ ],
[
'projection' => ['_id' => 1],
'sort' => ['scheduled_at' => 1],
diff --git a/src/Recruiter/Job/EventListener.php b/src/Recruiter/Job/EventListener.php
index cc2dc6d4..f82db1d1 100644
--- a/src/Recruiter/Job/EventListener.php
+++ b/src/Recruiter/Job/EventListener.php
@@ -4,5 +4,5 @@
interface EventListener
{
- public function onEvent($channel, Event $ev);
+ public function onEvent($channel, Event $ev): void;
}
diff --git a/src/Recruiter/JobExecution.php b/src/Recruiter/JobExecution.php
index 4c321b73..b84373c6 100644
--- a/src/Recruiter/JobExecution.php
+++ b/src/Recruiter/JobExecution.php
@@ -6,31 +6,31 @@
class JobExecution
{
- private $isCrashed;
- private $scheduledAt;
- private $startedAt;
- private $endedAt;
+ private bool $isCrashed = false;
+ private ?T\Moment $scheduledAt = null;
+ private ?T\Moment $startedAt = null;
+ private ?T\Moment $endedAt = null;
private $completedWith;
- private $failedWith;
+ private ?\Throwable $failedWith = null;
- public function isCrashed()
+ public function isCrashed(): bool
{
return $this->isCrashed;
}
- public function started($scheduledAt = null)
+ public function started(?T\Moment $scheduledAt = null): void
{
$this->scheduledAt = $scheduledAt;
$this->startedAt = T\now();
}
- public function failedWith(\Throwable $exception)
+ public function failedWith(\Throwable $exception): void
{
$this->endedAt = T\now();
$this->failedWith = $exception;
}
- public function completedWith($result)
+ public function completedWith($result): void
{
$this->endedAt = T\now();
$this->completedWith = $result;
@@ -41,17 +41,17 @@ public function result()
return $this->completedWith;
}
- public function causeOfFailure()
+ public function causeOfFailure(): ?\Throwable
{
return $this->failedWith;
}
- public function isFailed()
+ public function isFailed(): bool
{
return !is_null($this->failedWith) || $this->isCrashed();
}
- public function duration()
+ public function duration(): T\Interval
{
if ($this->startedAt && $this->endedAt && ($this->startedAt <= $this->endedAt)) {
return T\seconds(
@@ -63,7 +63,7 @@ public function duration()
return T\seconds(0);
}
- public static function import($document)
+ public static function import(array $document): self
{
$lastExecution = new self();
if (array_key_exists('last_execution', $document)) {
@@ -82,7 +82,7 @@ public static function import($document)
return $lastExecution;
}
- public function export()
+ public function export(): array
{
$exported = [];
if ($this->scheduledAt) {
@@ -95,7 +95,7 @@ public function export()
$exported['ended_at'] = T\MongoDate::from($this->endedAt);
}
if ($this->failedWith) {
- $exported['class'] = get_class($this->failedWith);
+ $exported['class'] = $this->failedWith::class;
$exported['message'] = $this->failedWith->getMessage();
$exported['trace'] = $this->traceOf($this->failedWith);
}
@@ -109,7 +109,7 @@ public function export()
}
}
- private function traceOf($result)
+ private function traceOf(mixed $result): string
{
$trace = 'ok';
if ($result instanceof \Throwable) {
@@ -117,11 +117,11 @@ private function traceOf($result)
} elseif (is_object($result) && method_exists($result, 'trace')) {
$trace = $result->trace();
} elseif (is_object($result)) {
- $trace = get_class($result);
+ $trace = $result::class;
} elseif (is_string($result) || is_numeric($result)) {
$trace = $result;
}
- return substr($trace, 0, 4096);
+ return substr((string) $trace, 0, 4096);
}
}
diff --git a/src/Recruiter/JobToSchedule.php b/src/Recruiter/JobToSchedule.php
index b6a21cff..cf260a7e 100644
--- a/src/Recruiter/JobToSchedule.php
+++ b/src/Recruiter/JobToSchedule.php
@@ -9,14 +9,11 @@
class JobToSchedule
{
- private $job;
-
/** @var bool */
private $mustBeScheduled;
- public function __construct(Job $job)
+ public function __construct(private readonly Job $job)
{
- $this->job = $job;
$this->mustBeScheduled = false;
}
@@ -67,7 +64,10 @@ public function scheduleAt(Moment $momentInTime)
return $this;
}
- public function inGroup($group)
+ /**
+ * @return $this
+ */
+ public function inGroup(array|string|null $group): static
{
if (!empty($group)) {
$this->job->inGroup($group);
@@ -76,7 +76,7 @@ public function inGroup($group)
return $this;
}
- public function taggedAs($tags)
+ public function taggedAs(array|string $tags): static
{
if (!empty($tags)) {
$this->job->taggedAs(is_array($tags) ? $tags : [$tags]);
@@ -85,21 +85,21 @@ public function taggedAs($tags)
return $this;
}
- public function withUrn(string $urn)
+ public function withUrn(string $urn): static
{
$this->job->withUrn($urn);
return $this;
}
- public function scheduledBy(string $namespace, string $id, int $nth)
+ public function scheduledBy(string $namespace, string $id, int $nth): static
{
$this->job->scheduledBy($namespace, $id, $nth);
return $this;
}
- public function execute()
+ public function execute(): string
{
if ($this->mustBeScheduled) {
$this->job->save();
@@ -110,7 +110,7 @@ public function execute()
return (string) $this->job->id();
}
- private function emptyEventDispatcher()
+ private function emptyEventDispatcher(): EventDispatcher
{
return new EventDispatcher();
}
@@ -122,12 +122,12 @@ public function __call($name, $arguments)
return $this->execute();
}
- public function export()
+ public function export(): array
{
return $this->job->export();
}
- public static function import($document, $repository)
+ public static function import($document, $repository): self
{
return new self(Job::import($document, $repository));
}
diff --git a/src/Recruiter/Recruiter.php b/src/Recruiter/Recruiter.php
index d1e58dff..a0138695 100644
--- a/src/Recruiter/Recruiter.php
+++ b/src/Recruiter/Recruiter.php
@@ -11,65 +11,64 @@
class Recruiter
{
- private $db;
- private $jobs;
- private $workers;
- private $scheduler;
- private $eventDispatcher;
+ private readonly Job\Repository $jobs;
+ private readonly Worker\Repository $workers;
+ private readonly Scheduler\Repository $scheduler;
+ private readonly EventDispatcher $eventDispatcher;
- public function __construct(MongoDB\Database $db)
+ public function __construct(private readonly MongoDB\Database $db)
{
- $this->db = $db;
- $this->jobs = new Job\Repository($db);
- $this->workers = new Worker\Repository($db, $this);
- $this->scheduler = new Scheduler\Repository($db);
+ $this->jobs = new Job\Repository($this->db);
+ $this->workers = new Worker\Repository($this->db, $this);
+ $this->scheduler = new Scheduler\Repository($this->db);
$this->eventDispatcher = new EventDispatcher();
}
- public function hire(MemoryLimit $memoryLimit)
+ public function hire(MemoryLimit $memoryLimit): Worker
{
return Worker::workFor($this, $this->workers, $memoryLimit);
}
- public function jobOf(Workable $workable)
+ public function jobOf(Workable $workable): JobToSchedule
{
return new JobToSchedule(
Job::around($workable, $this->jobs),
);
}
- public function repeatableJobOf(Repeatable $repeatable)
+ public function repeatableJobOf(Repeatable $repeatable): Scheduler
{
return Scheduler::around($repeatable, $this->scheduler, $this);
}
- public function queued()
+ public function queued(): int
{
return $this->jobs->queued();
}
- public function scheduled()
+ public function scheduled(): int
{
return $this->jobs->scheduledCount();
}
- public function queuedGroupedBy($field, array $query = [], $group = null)
+ public function queuedGroupedBy($field, array $query = [], $group = null): array
{
return $this->jobs->queuedGroupedBy($field, $query, $group);
}
- /**
- * @deprecated use the method `analytics` instead
- */
- public function statistics($group = null, ?Moment $at = null, array $query = [])
+ #[\Deprecated(message: 'use the method `analytics` instead')]
+ public function statistics($group = null, ?Moment $at = null, array $query = []): array
{
return $this->analytics($group, $at, $query);
}
- public function analytics($group = null, ?Moment $at = null, array $query = [])
+ /**
+ * @return array
+ */
+ public function analytics($group = null, ?Moment $at = null, array $query = []): array
{
$totalsScheduledJobs = $this->jobs->scheduledCount($group, $query);
- $queued = $this->jobs->queued($group, $at, $at ? $at->before(T\hour(24)) : null, $query);
+ $queued = $this->jobs->queued($group, $at, $at?->before(T\hour(24)), $query);
$postponed = $this->jobs->postponed($group, $at, $query);
return array_merge(
@@ -84,7 +83,7 @@ public function analytics($group = null, ?Moment $at = null, array $query = [])
);
}
- public function getEventDispatcher()
+ public function getEventDispatcher(): EventDispatcher
{
return $this->eventDispatcher;
}
@@ -94,7 +93,7 @@ public function getEventDispatcher()
*
* @return int how many
*/
- public function rollbackLockedJobs()
+ public function rollbackLockedJobs(): int
{
$assignedJobs = Worker::assignedJobs($this->db->selectCollection('roster'));
@@ -104,16 +103,16 @@ public function rollbackLockedJobs()
/**
* @step
*/
- public function bye()
+ public function bye(): void
{
}
- public function assignJobsToWorkers()
+ public function assignJobsToWorkers(): array
{
return $this->assignLockedJobsToWorkers($this->bookJobsForWorkers());
}
- public function scheduleRepeatableJobs()
+ public function scheduleRepeatableJobs(): void
{
$schedulers = $this->scheduler->all();
foreach ($schedulers as $scheduler) {
@@ -124,7 +123,7 @@ public function scheduleRepeatableJobs()
/**
* @step
*/
- public function bookJobsForWorkers()
+ public function bookJobsForWorkers(): array
{
$roster = $this->db->selectCollection('roster');
$scheduled = $this->db->selectCollection('scheduled');
@@ -150,7 +149,7 @@ public function bookJobsForWorkers()
/**
* @step
*/
- public function assignLockedJobsToWorkers($bookedJobs)
+ public function assignLockedJobsToWorkers(array $bookedJobs): array
{
$assignments = [];
$totalActualAssignments = 0;
@@ -169,9 +168,7 @@ public function assignLockedJobsToWorkers($bookedJobs)
}
return [
- array_map(function ($value) {
- return (string) $value;
- }, $assignments),
+ array_map(fn ($value) => (string) $value, $assignments),
$totalActualAssignments,
];
}
@@ -186,7 +183,7 @@ public function scheduledJob($id)
*
* @return int how many jobs were unlocked as a result
*/
- public function retireDeadWorkers(\DateTimeImmutable $now, Interval $consideredDeadAfter)
+ public function retireDeadWorkers(\DateTimeImmutable $now, Interval $consideredDeadAfter): int
{
return $this->jobs->releaseAll(
$jobsAssignedToDeadWorkers = Worker::retireDeadWorkers($this->workers, $now, $consideredDeadAfter),
@@ -204,7 +201,7 @@ public function flushJobsSynchronously(): SynchronousExecutionReport
return SynchronousExecutionReport::fromArray($report);
}
- public function createCollectionsAndIndexes()
+ public function createCollectionsAndIndexes(): void
{
$this->db->selectCollection('scheduled')->createIndex(
[
@@ -268,7 +265,7 @@ public function createCollectionsAndIndexes()
);
}
- private function combineJobsWithWorkers($jobs, $workers)
+ private function combineJobsWithWorkers($jobs, $workers): array
{
$assignments = min(count($workers), count($jobs));
$workers = array_slice($workers, 0, $assignments);
diff --git a/src/Recruiter/RepeatableInJob.php b/src/Recruiter/RepeatableInJob.php
index 5546e4f8..e6a23110 100644
--- a/src/Recruiter/RepeatableInJob.php
+++ b/src/Recruiter/RepeatableInJob.php
@@ -56,7 +56,7 @@ public static function initialize(): array
private static function classNameOf($repeatable): string
{
- $repeatableClassName = get_class($repeatable);
+ $repeatableClassName = $repeatable::class;
if (method_exists($repeatable, 'getClass')) {
$repeatableClassName = $repeatable->getClass();
}
diff --git a/src/Recruiter/RetryPolicy.php b/src/Recruiter/RetryPolicy.php
index 4acb51b5..33f29590 100644
--- a/src/Recruiter/RetryPolicy.php
+++ b/src/Recruiter/RetryPolicy.php
@@ -13,10 +13,8 @@ interface RetryPolicy
* - schedule the job
* - archive the job
* - do nothing (and the job will be archived anyway)
- *
- * @return void
*/
- public function schedule(JobAfterFailure $job);
+ public function schedule(JobAfterFailure $job): void;
/**
* Export retry policy parameters.
diff --git a/src/Recruiter/RetryPolicy/DoNotDoItAgain.php b/src/Recruiter/RetryPolicy/DoNotDoItAgain.php
index 5ae8288a..fafe975b 100644
--- a/src/Recruiter/RetryPolicy/DoNotDoItAgain.php
+++ b/src/Recruiter/RetryPolicy/DoNotDoItAgain.php
@@ -11,7 +11,7 @@ class DoNotDoItAgain implements RetryPolicy
{
use RetryPolicyBehaviour;
- public function schedule(JobAfterFailure $job)
+ public function schedule(JobAfterFailure $job): void
{
// doing nothing means to avoid to reschedule the job
}
diff --git a/src/Recruiter/RetryPolicy/ExponentialBackoff.php b/src/Recruiter/RetryPolicy/ExponentialBackoff.php
index 9db868fc..b1bcedb7 100644
--- a/src/Recruiter/RetryPolicy/ExponentialBackoff.php
+++ b/src/Recruiter/RetryPolicy/ExponentialBackoff.php
@@ -12,15 +12,15 @@
class ExponentialBackoff implements RetryPolicy
{
use RetryPolicyBehaviour;
- private $retryHowManyTimes;
- private $timeToInitiallyWaitBeforeRetry;
- public static function forTimes($retryHowManyTimes, $timeToInitiallyWaitBeforeRetry = 60)
+ private Interval $timeToInitiallyWaitBeforeRetry;
+
+ public static function forTimes($retryHowManyTimes, $timeToInitiallyWaitBeforeRetry = 60): static
{
return new static($retryHowManyTimes, $timeToInitiallyWaitBeforeRetry);
}
- public function atFirstWaiting($timeToInitiallyWaitBeforeRetry)
+ public function atFirstWaiting($timeToInitiallyWaitBeforeRetry): static
{
return new static($this->retryHowManyTimes, $timeToInitiallyWaitBeforeRetry);
}
@@ -29,7 +29,7 @@ public function atFirstWaiting($timeToInitiallyWaitBeforeRetry)
* @params integer $interval in seconds
* @params integer $timeToWaitBeforeRetry in seconds
*/
- public static function forAnInterval($interval, $timeToInitiallyWaitBeforeRetry)
+ public static function forAnInterval($interval, $timeToInitiallyWaitBeforeRetry): static
{
if (!($timeToInitiallyWaitBeforeRetry instanceof Interval)) {
$timeToInitiallyWaitBeforeRetry = T\seconds($timeToInitiallyWaitBeforeRetry);
@@ -42,19 +42,18 @@ public static function forAnInterval($interval, $timeToInitiallyWaitBeforeRetry)
return new static($numberOfRetries, $timeToInitiallyWaitBeforeRetry);
}
- public function __construct($retryHowManyTimes, $timeToInitiallyWaitBeforeRetry)
+ public function __construct(private $retryHowManyTimes, int|Interval $timeToInitiallyWaitBeforeRetry)
{
if (!($timeToInitiallyWaitBeforeRetry instanceof Interval)) {
$timeToInitiallyWaitBeforeRetry = T\seconds($timeToInitiallyWaitBeforeRetry);
}
- $this->retryHowManyTimes = $retryHowManyTimes;
$this->timeToInitiallyWaitBeforeRetry = $timeToInitiallyWaitBeforeRetry;
}
- public function schedule(JobAfterFailure $job)
+ public function schedule(JobAfterFailure $job): void
{
if ($job->numberOfAttempts() <= $this->retryHowManyTimes) {
- $retryInterval = T\seconds(pow(2, $job->numberOfAttempts() - 1) * $this->timeToInitiallyWaitBeforeRetry->seconds());
+ $retryInterval = T\seconds(2 ** ($job->numberOfAttempts() - 1) * $this->timeToInitiallyWaitBeforeRetry->seconds());
$job->scheduleIn($retryInterval);
} else {
$job->archive('tried-too-many-times');
diff --git a/src/Recruiter/RetryPolicy/RetriableException.php b/src/Recruiter/RetryPolicy/RetriableException.php
index 30546a73..896f32cc 100644
--- a/src/Recruiter/RetryPolicy/RetriableException.php
+++ b/src/Recruiter/RetryPolicy/RetriableException.php
@@ -9,10 +9,7 @@ class RetriableException
/** @var string */
private $exceptionClass;
- /** @var RetryPolicy */
- private $retryPolicy;
-
- public function __construct(string $exceptionClass, RetryPolicy $retryPolicy)
+ public function __construct(string $exceptionClass, private readonly RetryPolicy $retryPolicy)
{
if (!class_exists($exceptionClass)) {
throw new \InvalidArgumentException("Class $exceptionClass doesn't exists");
@@ -21,7 +18,6 @@ public function __construct(string $exceptionClass, RetryPolicy $retryPolicy)
throw new \InvalidArgumentException("Class $exceptionClass is not Throwable");
}
$this->exceptionClass = $exceptionClass;
- $this->retryPolicy = $retryPolicy;
}
public function exceptionClass(): string
diff --git a/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php b/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
index bc4e2203..acfbfa81 100644
--- a/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
+++ b/src/Recruiter/RetryPolicy/RetriableExceptionFilter.php
@@ -8,7 +8,6 @@
class RetriableExceptionFilter implements RetryPolicy
{
- private $filteredRetryPolicy;
private $retriableExceptions;
/**
@@ -21,13 +20,12 @@ public static function onlyFor($exceptionClass, RetryPolicy $retryPolicy)
return new self($retryPolicy, [$exceptionClass]);
}
- public function __construct(RetryPolicy $filteredRetryPolicy, array $retriableExceptions = ['Exception'])
+ public function __construct(private readonly RetryPolicy $filteredRetryPolicy, array $retriableExceptions = ['Exception'])
{
- $this->filteredRetryPolicy = $filteredRetryPolicy;
$this->retriableExceptions = $this->ensureAreAllExceptions($retriableExceptions);
}
- public function schedule(JobAfterFailure $job)
+ public function schedule(JobAfterFailure $job): void
{
if ($this->isExceptionRetriable($job->causeOfFailure())) {
$this->filteredRetryPolicy->schedule($job);
@@ -41,7 +39,7 @@ public function export(): array
return [
'retriable_exceptions' => $this->retriableExceptions,
'filtered_retry_policy' => [
- 'class' => get_class($this->filteredRetryPolicy),
+ 'class' => $this->filteredRetryPolicy::class,
'parameters' => $this->filteredRetryPolicy->export(),
],
];
@@ -76,12 +74,10 @@ private function ensureAreAllExceptions($exceptions)
private function isExceptionRetriable($exception)
{
- if (!is_null($exception) && is_object($exception)) {
+ if (is_object($exception)) {
return array_any(
$this->retriableExceptions,
- function ($retriableExceptionType) use ($exception) {
- return $exception instanceof $retriableExceptionType;
- },
+ fn ($retriableExceptionType) => $exception instanceof $retriableExceptionType,
);
}
diff --git a/src/Recruiter/RetryPolicy/RetryForever.php b/src/Recruiter/RetryPolicy/RetryForever.php
index 57105fd1..4ec6c57d 100644
--- a/src/Recruiter/RetryPolicy/RetryForever.php
+++ b/src/Recruiter/RetryPolicy/RetryForever.php
@@ -14,7 +14,7 @@ final class RetryForever implements RetryPolicy
use RetryPolicyBehaviour;
private $timeToWaitBeforeRetry;
- public function __construct($timeToWaitBeforeRetry)
+ public function __construct(int|Interval $timeToWaitBeforeRetry)
{
if (!($timeToWaitBeforeRetry instanceof Interval)) {
$timeToWaitBeforeRetry = T\seconds($timeToWaitBeforeRetry);
@@ -22,12 +22,12 @@ public function __construct($timeToWaitBeforeRetry)
$this->timeToWaitBeforeRetry = $timeToWaitBeforeRetry;
}
- public static function afterSeconds($timeToWaitBeforeRetry = 60)
+ public static function afterSeconds(int|Interval $timeToWaitBeforeRetry = 60): self
{
- return new static($timeToWaitBeforeRetry);
+ return new self($timeToWaitBeforeRetry);
}
- public function schedule(JobAfterFailure $job)
+ public function schedule(JobAfterFailure $job): void
{
$job->scheduleIn($this->timeToWaitBeforeRetry);
}
diff --git a/src/Recruiter/RetryPolicy/RetryManyTimes.php b/src/Recruiter/RetryPolicy/RetryManyTimes.php
index fa599ebe..d5fa7d02 100644
--- a/src/Recruiter/RetryPolicy/RetryManyTimes.php
+++ b/src/Recruiter/RetryPolicy/RetryManyTimes.php
@@ -12,24 +12,23 @@
class RetryManyTimes implements RetryPolicy
{
use RetryPolicyBehaviour;
- private $retryHowManyTimes;
- private $timeToWaitBeforeRetry;
- public function __construct($retryHowManyTimes, $timeToWaitBeforeRetry)
+ private Interval $timeToWaitBeforeRetry;
+
+ public function __construct(private readonly int $retryHowManyTimes, int|Interval $timeToWaitBeforeRetry)
{
if (!($timeToWaitBeforeRetry instanceof Interval)) {
$timeToWaitBeforeRetry = T\seconds($timeToWaitBeforeRetry);
}
- $this->retryHowManyTimes = $retryHowManyTimes;
$this->timeToWaitBeforeRetry = $timeToWaitBeforeRetry;
}
- public static function forTimes($retryHowManyTimes, $timeToWaitBeforeRetry = 60)
+ public static function forTimes($retryHowManyTimes, int|Interval $timeToWaitBeforeRetry = 60): static
{
return new static($retryHowManyTimes, $timeToWaitBeforeRetry);
}
- public function schedule(JobAfterFailure $job)
+ public function schedule(JobAfterFailure $job): void
{
if ($job->numberOfAttempts() <= $this->retryHowManyTimes) {
$job->scheduleIn($this->timeToWaitBeforeRetry);
diff --git a/src/Recruiter/RetryPolicy/SelectByException.php b/src/Recruiter/RetryPolicy/SelectByException.php
index 98d814f4..e00bafe6 100644
--- a/src/Recruiter/RetryPolicy/SelectByException.php
+++ b/src/Recruiter/RetryPolicy/SelectByException.php
@@ -24,22 +24,23 @@
*/
class SelectByException implements RetryPolicy
{
- /**
- * @var array
- */
- private $exceptions;
-
public static function create(): SelectByExceptionBuilder
{
return new SelectByExceptionBuilder();
}
- public function __construct(array $exceptions)
- {
- $this->exceptions = $exceptions;
+ public function __construct(
+ /**
+ * @var array
+ */
+ private readonly array $exceptions,
+ ) {
}
- public function schedule(JobAfterFailure $job)
+ /**
+ * @throws \Exception
+ */
+ public function schedule(JobAfterFailure $job): void
{
$exception = $job->causeOfFailure();
if ($this->isRetriable($exception)) {
@@ -58,7 +59,7 @@ function (RetriableException $retriableException) {
return [
'when' => $retriableException->exceptionClass(),
'then' => [
- 'class' => get_class($retryPolicy),
+ 'class' => $retryPolicy::class,
'parameters' => $retryPolicy->export(),
],
];
@@ -89,9 +90,7 @@ public function isLastRetry(Job $job): bool
// I cannot answer to that so... true only if everybody says true
return array_all(
$this->exceptions,
- function (RetriableException $retriableException) use ($job) {
- return $retriableException->retryPolicy()->isLastRetry($job);
- },
+ fn (RetriableException $retriableException) => $retriableException->retryPolicy()->isLastRetry($job),
);
}
@@ -101,11 +100,14 @@ private function isRetriable($exception): bool
$this->retryPolicyFor($exception);
return true;
- } catch (\Exception $e) {
+ } catch (\Exception) {
return false;
}
}
+ /**
+ * @throws \Exception
+ */
private function retryPolicyFor(?object $exception): RetryPolicy
{
if (!is_null($exception) && is_object($exception)) {
@@ -117,7 +119,7 @@ private function retryPolicyFor(?object $exception): RetryPolicy
}
}
if ($exception instanceof \Throwable) {
- throw new \Exception('Unable to find a RetryPolicy associated to exception: ' . get_class($exception), 0, $exception);
+ throw new \Exception('Unable to find a RetryPolicy associated to exception: ' . $exception::class, 0, $exception);
}
}
throw new \Exception('Unable to find a RetryPolicy associated to: ' . var_export($exception, true));
diff --git a/src/Recruiter/RetryPolicy/TimeTable.php b/src/Recruiter/RetryPolicy/TimeTable.php
index b7d65d19..eec7a965 100644
--- a/src/Recruiter/RetryPolicy/TimeTable.php
+++ b/src/Recruiter/RetryPolicy/TimeTable.php
@@ -11,11 +11,13 @@
class TimeTable implements RetryPolicy
{
use RetryPolicyBehaviour;
- /** @var array */
- private $timeTable;
+ private ?array $timeTable;
- private $howManyRetries;
+ private int $howManyRetries;
+ /**
+ * @throws \Exception
+ */
public function __construct(?array $timeTable)
{
if (is_null($timeTable)) {
@@ -29,7 +31,7 @@ public function __construct(?array $timeTable)
$this->howManyRetries = self::estimateHowManyRetriesIn($timeTable);
}
- public function schedule(JobAfterFailure $job)
+ public function schedule(JobAfterFailure $job): void
{
foreach ($this->timeTable as $timeSpent => $rescheduleIn) {
if ($this->hasBeenCreatedLessThan($job, $timeSpent)) {
@@ -60,28 +62,28 @@ public static function import(array $parameters): RetryPolicy
private function hasBeenCreatedLessThan($job, $relativeTime)
{
return $job->createdAt()->isAfter(
- T\Moment::fromTimestamp(strtotime($relativeTime, T\now()->seconds())),
+ T\Moment::fromTimestamp(strtotime((string) $relativeTime, T\now()->seconds())),
);
}
- private function rescheduleIn($job, $relativeTime)
+ private function rescheduleIn($job, $relativeTime): void
{
$job->scheduleAt(
- T\Moment::fromTimestamp(strtotime($relativeTime, T\now()->seconds())),
+ T\Moment::fromTimestamp(strtotime((string) $relativeTime, T\now()->seconds())),
);
}
- private static function estimateHowManyRetriesIn($timeTable)
+ private static function estimateHowManyRetriesIn(array $timeTable): int
{
$now = T\now()->seconds();
$howManyRetries = 0;
$timeWindowInSeconds = 0;
foreach ($timeTable as $timeWindow => $rescheduleTime) {
- $timeWindowInSeconds = ($now - strtotime($timeWindow, $now)) - $timeWindowInSeconds;
+ $timeWindowInSeconds = ($now - strtotime((string) $timeWindow, $now)) - $timeWindowInSeconds;
if ($timeWindowInSeconds <= 0) {
throw new \Exception("Time window `$timeWindow` is invalid, must be in the past");
}
- $rescheduleTimeInSeconds = (strtotime($rescheduleTime, $now) - $now);
+ $rescheduleTimeInSeconds = (strtotime((string) $rescheduleTime, $now) - $now);
if ($rescheduleTimeInSeconds <= 0) {
throw new \Exception("Reschedule time `$rescheduleTime` is invalid, must be in the future");
}
diff --git a/src/Recruiter/RetryPolicyBehaviour.php b/src/Recruiter/RetryPolicyBehaviour.php
index d934bec6..caea789a 100644
--- a/src/Recruiter/RetryPolicyBehaviour.php
+++ b/src/Recruiter/RetryPolicyBehaviour.php
@@ -23,7 +23,7 @@ public function retryOnlyWhenExceptionsAre($retriableExceptionTypes)
return new RetriableExceptionFilter($this, $retriableExceptionTypes);
}
- public function schedule(JobAfterFailure $job)
+ public function schedule(JobAfterFailure $job): void
{
throw new \Exception('RetryPolicy::schedule(JobAfterFailure) need to be implemented');
}
diff --git a/src/Recruiter/RetryPolicyInJob.php b/src/Recruiter/RetryPolicyInJob.php
index 625645dc..dd5b5205 100644
--- a/src/Recruiter/RetryPolicyInJob.php
+++ b/src/Recruiter/RetryPolicyInJob.php
@@ -27,7 +27,7 @@ public static function export($retryPolicy)
{
return [
'retry_policy' => [
- 'class' => get_class($retryPolicy),
+ 'class' => $retryPolicy::class,
'parameters' => $retryPolicy->export(),
],
];
diff --git a/src/Recruiter/SchedulePolicy/Cron.php b/src/Recruiter/SchedulePolicy/Cron.php
index 8a3825fe..73e42f86 100644
--- a/src/Recruiter/SchedulePolicy/Cron.php
+++ b/src/Recruiter/SchedulePolicy/Cron.php
@@ -8,13 +8,8 @@
class Cron implements SchedulePolicy
{
- private $cronExpression;
- private $now;
-
- public function __construct(string $cronExpression, ?\DateTime $now = null)
+ public function __construct(private readonly string $cronExpression, private readonly ?\DateTime $now = null)
{
- $this->cronExpression = $cronExpression;
- $this->now = $now;
}
public function next(): Moment
diff --git a/src/Recruiter/SchedulePolicyInJob.php b/src/Recruiter/SchedulePolicyInJob.php
index 3f376346..184b9242 100644
--- a/src/Recruiter/SchedulePolicyInJob.php
+++ b/src/Recruiter/SchedulePolicyInJob.php
@@ -27,7 +27,7 @@ public static function export($schedulePolicy)
{
return [
'schedule_policy' => [
- 'class' => get_class($schedulePolicy),
+ 'class' => $schedulePolicy::class,
'parameters' => $schedulePolicy->export(),
],
];
diff --git a/src/Recruiter/Scheduler.php b/src/Recruiter/Scheduler.php
index b6d8dd36..409c17ff 100644
--- a/src/Recruiter/Scheduler.php
+++ b/src/Recruiter/Scheduler.php
@@ -10,16 +10,6 @@ class Scheduler
{
private $job;
- private $schedulers;
-
- private $status;
-
- private $schedulePolicy;
-
- private $repeatable;
-
- private $retryPolicy;
-
public static function around(Repeatable $repeatable, Repository $repository, Recruiter $recruiter)
{
$retryPolicy = ($repeatable instanceof Retriable) ?
@@ -46,18 +36,8 @@ public static function import($document, Repository $repository)
);
}
- public function __construct(
- array $status,
- Repeatable $repeatable,
- ?SchedulePolicy $schedulePolicy,
- ?RetryPolicy $retryPolicy,
- Repository $schedulers,
- ) {
- $this->status = $status;
- $this->repeatable = $repeatable;
- $this->schedulePolicy = $schedulePolicy;
- $this->retryPolicy = $retryPolicy;
- $this->schedulers = $schedulers;
+ public function __construct(private array $status, private readonly Repeatable $repeatable, private ?SchedulePolicy $schedulePolicy, private ?RetryPolicy $retryPolicy, private readonly Repository $schedulers)
+ {
}
public function create()
@@ -122,7 +102,7 @@ private function aJobIsStillRunning(JobsRepository $jobs)
$alreadyScheduledJob = $jobs->scheduled($this->status['last_scheduling']['job_id']);
return true;
- } catch (\Throwable $e) {
+ } catch (\Throwable) {
return false;
}
}
@@ -147,7 +127,7 @@ public function schedule(JobsRepository $jobs)
++$this->status['attempts'];
$this->schedulers->save($this);
- $jobToSchedule = (new JobToSchedule(Job::around($this->repeatable, $jobs)))
+ $jobToSchedule = new JobToSchedule(Job::around($this->repeatable, $jobs))
->scheduleAt($nextScheduling)
->retryWithPolicy($this->retryPolicy)
->scheduledBy('scheduler', $this->status['urn'], $this->status['attempts'])
diff --git a/src/Recruiter/Scheduler/Repository.php b/src/Recruiter/Scheduler/Repository.php
index 61f8e3c0..d22ccb96 100644
--- a/src/Recruiter/Scheduler/Repository.php
+++ b/src/Recruiter/Scheduler/Repository.php
@@ -40,13 +40,11 @@ public function create(Scheduler $scheduler)
if (0 === $this->schedulers->count(['urn' => $document['urn']])) {
$this->schedulers->insertOne($document);
} else {
- $document = array_filter($document, function ($key) {
- return in_array($key, [
- 'job',
- 'schedule_policy',
- 'unique',
- ]);
- }, ARRAY_FILTER_USE_KEY);
+ $document = array_filter($document, fn ($key) => in_array($key, [
+ 'job',
+ 'schedule_policy',
+ 'unique',
+ ]), ARRAY_FILTER_USE_KEY);
$this->schedulers->updateOne(
['urn' => $scheduler->urn()],
diff --git a/src/Recruiter/SynchronousExecutionReport.php b/src/Recruiter/SynchronousExecutionReport.php
index 2775aa5e..f2f80cda 100644
--- a/src/Recruiter/SynchronousExecutionReport.php
+++ b/src/Recruiter/SynchronousExecutionReport.php
@@ -9,17 +9,11 @@
*/
class SynchronousExecutionReport
{
- /**
- * @var array
- */
- private $data;
-
/**
* @param array $data = []
*/
- public function __construct(array $data = [])
+ public function __construct(private readonly array $data = [])
{
- $this->data = $data;
}
/**
@@ -32,9 +26,7 @@ public static function fromArray(array $data): SynchronousExecutionReport
public function isThereAFailure(): bool
{
- return array_any($this->data, function ($jobExecution, $jobId) {
- return $jobExecution->isFailed();
- });
+ return array_any($this->data, fn ($jobExecution, $jobId) => $jobExecution->isFailed());
}
public function toArray()
diff --git a/src/Recruiter/Taggable.php b/src/Recruiter/Taggable.php
index 0e9354e3..0d2e37db 100644
--- a/src/Recruiter/Taggable.php
+++ b/src/Recruiter/Taggable.php
@@ -7,7 +7,7 @@ interface Taggable
/**
* A Job can decide its own tags. Tags are useful to correlate jobs.
*
- * @return array Strings to be used to tag the job
+ * @return array Strings to be used to tag the job
*/
- public function taggedAs();
+ public function taggedAs(): array;
}
diff --git a/src/Recruiter/WaitStrategy.php b/src/Recruiter/WaitStrategy.php
index 0b71e42f..8278023c 100644
--- a/src/Recruiter/WaitStrategy.php
+++ b/src/Recruiter/WaitStrategy.php
@@ -9,14 +9,12 @@ class WaitStrategy
private $timeToWaitAtLeast;
private $timeToWaitAtMost;
private $timeToWait;
- private $howToWait;
- public function __construct(Interval $timeToWaitAtLeast, Interval $timeToWaitAtMost, $howToWait = 'usleep')
+ public function __construct(Interval $timeToWaitAtLeast, Interval $timeToWaitAtMost, private $howToWait = 'usleep')
{
$this->timeToWaitAtLeast = $timeToWaitAtLeast->milliseconds();
$this->timeToWaitAtMost = $timeToWaitAtMost->milliseconds();
$this->timeToWait = $timeToWaitAtLeast->milliseconds();
- $this->howToWait = $howToWait;
}
public function reset()
diff --git a/src/Recruiter/Workable/AlwaysFail.php b/src/Recruiter/Workable/AlwaysFail.php
index 3a90f1fa..f0439e11 100644
--- a/src/Recruiter/Workable/AlwaysFail.php
+++ b/src/Recruiter/Workable/AlwaysFail.php
@@ -9,7 +9,7 @@ class AlwaysFail implements Workable
{
use WorkableBehaviour;
- public function execute()
+ public function execute(): never
{
throw new \Exception('Sorry, I\'m good for nothing');
}
diff --git a/src/Recruiter/Workable/FactoryMethodCommand.php b/src/Recruiter/Workable/FactoryMethodCommand.php
index deac6c23..431871bb 100644
--- a/src/Recruiter/Workable/FactoryMethodCommand.php
+++ b/src/Recruiter/Workable/FactoryMethodCommand.php
@@ -12,7 +12,7 @@ public static function from(/* $callable[, $argument, $argument...] */)
{
$arguments = func_get_args();
$callable = array_shift($arguments);
- [$class, $method] = explode('::', $callable);
+ [$class, $method] = explode('::', (string) $callable);
return self::singleStep(self::stepFor($class, $method, $arguments));
}
@@ -37,11 +37,8 @@ private static function stepFor($class, $method, $arguments)
return $step;
}
- private $steps;
-
- private function __construct(array $steps = [])
+ private function __construct(private array $steps = [])
{
- $this->steps = $steps;
}
public function asJobOf(Recruiter $recruiter): JobToSchedule
@@ -62,7 +59,7 @@ public function execute($retryOptions = null)
if (!is_callable($callable)) {
$message = 'The following step does not result in a callable: ' . var_export($step, true) . '.';
if (is_object($result)) {
- $message .= ' Reached object: ' . get_class($result);
+ $message .= ' Reached object: ' . $result::class;
} else {
$message .= ' Reached value: ' . var_export($result, true);
}
@@ -83,7 +80,7 @@ public function execute($retryOptions = null)
private function arguments($step)
{
- $arguments = isset($step['arguments']) ? $step['arguments'] : [];
+ $arguments = $step['arguments'] ?? [];
return $arguments;
}
diff --git a/src/Recruiter/Workable/LazyBones.php b/src/Recruiter/Workable/LazyBones.php
index d2c99115..29a3c285 100644
--- a/src/Recruiter/Workable/LazyBones.php
+++ b/src/Recruiter/Workable/LazyBones.php
@@ -25,7 +25,7 @@ public function __construct(private readonly int $usToSleep = 1, private readonl
public function execute(): void
{
- usleep($this->usToSleep + rand(intval(-$this->usOfDelta), $this->usOfDelta));
+ usleep($this->usToSleep + random_int(intval(-$this->usOfDelta), $this->usOfDelta));
}
public function export(): array
diff --git a/src/Recruiter/Workable/RecoverRepeatableFromException.php b/src/Recruiter/Workable/RecoverRepeatableFromException.php
index 4521f879..bb33d04e 100644
--- a/src/Recruiter/Workable/RecoverRepeatableFromException.php
+++ b/src/Recruiter/Workable/RecoverRepeatableFromException.php
@@ -9,19 +9,14 @@ class RecoverRepeatableFromException implements Repeatable
{
use WorkableBehaviour;
- protected $recoverForClass;
- protected $recoverForException;
-
- public function __construct($parameters, $recoverForClass, $recoverForException)
+ public function __construct($parameters, protected $recoverForClass, protected $recoverForException)
{
$this->parameters = $parameters;
- $this->recoverForClass = $recoverForClass;
- $this->recoverForException = $recoverForException;
}
- public function execute()
+ public function execute(): never
{
- throw new \Exception('This job failed while instantiating a workable of class: ' . $this->recoverForClass . PHP_EOL . 'Original exception: ' . get_class($this->recoverForException) . PHP_EOL . $this->recoverForException->getMessage() . PHP_EOL . $this->recoverForException->getTraceAsString() . PHP_EOL);
+ throw new \Exception('This job failed while instantiating a workable of class: ' . $this->recoverForClass . PHP_EOL . 'Original exception: ' . $this->recoverForException::class . PHP_EOL . $this->recoverForException->getMessage() . PHP_EOL . $this->recoverForException->getTraceAsString() . PHP_EOL);
}
public function getClass()
diff --git a/src/Recruiter/Workable/RecoverWorkableFromException.php b/src/Recruiter/Workable/RecoverWorkableFromException.php
index 6993f755..ebeacc86 100644
--- a/src/Recruiter/Workable/RecoverWorkableFromException.php
+++ b/src/Recruiter/Workable/RecoverWorkableFromException.php
@@ -9,19 +9,14 @@ class RecoverWorkableFromException implements Workable
{
use WorkableBehaviour;
- protected $recoverForClass;
- protected $recoverForException;
-
- public function __construct($parameters, $recoverForClass, $recoverForException)
+ public function __construct($parameters, protected $recoverForClass, protected $recoverForException)
{
$this->parameters = $parameters;
- $this->recoverForClass = $recoverForClass;
- $this->recoverForException = $recoverForException;
}
- public function execute()
+ public function execute(): never
{
- throw new \Exception('This job failed while instantiating a workable of class: ' . $this->recoverForClass . PHP_EOL . 'Original exception: ' . get_class($this->recoverForException) . PHP_EOL . $this->recoverForException->getMessage() . PHP_EOL . $this->recoverForException->getTraceAsString() . PHP_EOL);
+ throw new \Exception('This job failed while instantiating a workable of class: ' . $this->recoverForClass . PHP_EOL . 'Original exception: ' . $this->recoverForException::class . PHP_EOL . $this->recoverForException->getMessage() . PHP_EOL . $this->recoverForException->getTraceAsString() . PHP_EOL);
}
public function getClass()
diff --git a/src/Recruiter/Workable/SampleRepeatableCommand.php b/src/Recruiter/Workable/SampleRepeatableCommand.php
index 62faad5c..07bb97be 100644
--- a/src/Recruiter/Workable/SampleRepeatableCommand.php
+++ b/src/Recruiter/Workable/SampleRepeatableCommand.php
@@ -14,7 +14,7 @@ class SampleRepeatableCommand implements Workable, Repeatable
public function execute()
{
- var_export((new \DateTime())->format('c'));
+ var_export(new \DateTime()->format('c'));
}
public function urn(): string
diff --git a/src/Recruiter/Workable/ShellCommand.php b/src/Recruiter/Workable/ShellCommand.php
index 2e763704..c92778cc 100644
--- a/src/Recruiter/Workable/ShellCommand.php
+++ b/src/Recruiter/Workable/ShellCommand.php
@@ -9,16 +9,13 @@ class ShellCommand implements Workable
{
use WorkableBehaviour;
- private $commandLine;
-
public static function fromCommandLine($commandLine)
{
return new self($commandLine);
}
- private function __construct($commandLine)
+ private function __construct(private $commandLine)
{
- $this->commandLine = $commandLine;
}
public function execute()
diff --git a/src/Recruiter/WorkableBehaviour.php b/src/Recruiter/WorkableBehaviour.php
index 2f6d20e5..dd6f40e3 100644
--- a/src/Recruiter/WorkableBehaviour.php
+++ b/src/Recruiter/WorkableBehaviour.php
@@ -13,7 +13,7 @@ public function asJobOf(Recruiter $recruiter): JobToSchedule
return $recruiter->jobOf($this);
}
- public function execute()
+ public function execute(): never
{
throw new \Exception('Workable::execute() need to be implemented');
}
diff --git a/src/Recruiter/WorkableInJob.php b/src/Recruiter/WorkableInJob.php
index d53241dc..f09b7f87 100644
--- a/src/Recruiter/WorkableInJob.php
+++ b/src/Recruiter/WorkableInJob.php
@@ -55,7 +55,7 @@ public static function initialize()
private static function classNameOf($workable)
{
- $workableClassName = get_class($workable);
+ $workableClassName = $workable::class;
if (method_exists($workable, 'getClass')) {
$workableClassName = $workable->getClass();
}
diff --git a/src/Recruiter/Worker.php b/src/Recruiter/Worker.php
index e9885622..072d5e3c 100644
--- a/src/Recruiter/Worker.php
+++ b/src/Recruiter/Worker.php
@@ -12,11 +12,6 @@
class Worker
{
- private $status;
- private $recruiter;
- private $repository;
- private $memoryLimit;
-
public static function workFor(
Recruiter $recruiter,
Repository $repository,
@@ -28,16 +23,8 @@ public static function workFor(
return $worker;
}
- public function __construct(
- $status,
- Recruiter $recruiter,
- Repository $repository,
- MemoryLimit $memoryLimit,
- ) {
- $this->status = $status;
- $this->recruiter = $recruiter;
- $this->repository = $repository;
- $this->memoryLimit = $memoryLimit;
+ public function __construct(private $status, private readonly Recruiter $recruiter, private readonly Repository $repository, private readonly MemoryLimit $memoryLimit)
+ {
}
public function id()
@@ -131,7 +118,7 @@ private function afterExecutionOf($job)
date('c'),
$this->id(),
$job->id(),
- get_class($e),
+ $e::class,
$e->getMessage(),
);
@@ -208,9 +195,7 @@ public static function pickAvailableWorkers(MongoCollection $collection, $worker
if (count($workers) > 0) {
$unitsOfWorkers = array_group_by(
$workers,
- function ($worker) {
- return $worker['work_on'];
- },
+ fn ($worker) => $worker['work_on'],
);
foreach ($unitsOfWorkers as $workOn => $workersInUnit) {
$workersInUnit = array_column($workersInUnit, '_id');
@@ -225,9 +210,7 @@ function ($worker) {
public static function tryToAssignJobsToWorkers(MongoCollection $collection, $jobs, $workers)
{
$assignment = array_combine(
- array_map(function ($id) {
- return (string) $id;
- }, $workers),
+ array_map(fn ($id) => (string) $id, $workers),
$jobs,
);
diff --git a/src/Recruiter/Worker/Process.php b/src/Recruiter/Worker/Process.php
index 2dd02853..815be80f 100644
--- a/src/Recruiter/Worker/Process.php
+++ b/src/Recruiter/Worker/Process.php
@@ -6,26 +6,23 @@
class Process
{
- private $pid;
-
- public static function withPid($pid)
+ public static function withPid(int $pid)
{
return new self($pid);
}
- public function __construct($pid)
+ public function __construct(private readonly int $pid)
{
- $this->pid = $pid;
}
- public function cleanUp(Repository $repository)
+ public function cleanUp(Repository $repository): void
{
if (!$this->isAlive()) {
$repository->retireWorkerWithPid($this->pid);
}
}
- public function ifDead()
+ public function ifDead(): BlackHole|static
{
if ($this->isAlive()) {
return new BlackHole();
@@ -34,7 +31,7 @@ public function ifDead()
return $this;
}
- protected function isAlive()
+ protected function isAlive(): bool
{
return posix_kill($this->pid, 0);
}
diff --git a/src/Recruiter/Worker/Repository.php b/src/Recruiter/Worker/Repository.php
index 1e04a7d4..74fd14a9 100644
--- a/src/Recruiter/Worker/Repository.php
+++ b/src/Recruiter/Worker/Repository.php
@@ -9,12 +9,10 @@
class Repository
{
private $roster;
- private $recruiter;
- public function __construct(MongoDB\Database $db, Recruiter $recruiter)
+ public function __construct(MongoDB\Database $db, private readonly Recruiter $recruiter)
{
$this->roster = $db->selectCollection('roster');
- $this->recruiter = $recruiter;
}
public function save($worker)
diff --git a/src/Recruiter/functions.php b/src/Recruiter/functions.php
index 7e501820..00543400 100644
--- a/src/Recruiter/functions.php
+++ b/src/Recruiter/functions.php
@@ -4,9 +4,7 @@
function array_group_by($array, ?callable $f = null): array
{
- $f = $f ?: function ($value) {
- return $value;
- };
+ $f = $f ?: (fn ($value) => $value);
return array_reduce(
$array,
diff --git a/src/Sink/BlackHole.php b/src/Sink/BlackHole.php
index e94c724c..e4571ee6 100644
--- a/src/Sink/BlackHole.php
+++ b/src/Sink/BlackHole.php
@@ -5,7 +5,7 @@
use ArrayAccess;
use Iterator;
-class BlackHole implements \Iterator, \ArrayAccess
+class BlackHole implements \Iterator, \ArrayAccess, \Stringable
{
public function __construct()
{
From a43b46f61f8d0a0491522c95a2ed20d4483ca1e2 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 21:26:31 +0200
Subject: [PATCH 38/59] Increase rector level to 3
---
rector.php | 5 ++--
spec/Recruiter/Job/RepositoryTest.php | 7 +++---
.../RetryPolicy/ExponentialBackoffTest.php | 5 ++--
.../RetriableExceptionFilterTest.php | 4 ++--
.../RetryPolicy/SelectByExceptionTest.php | 24 ++++++++++---------
spec/Recruiter/RetryPolicy/TimeTableTest.php | 5 ++--
spec/Recruiter/WorkerProcessTest.php | 8 +++----
7 files changed, 32 insertions(+), 26 deletions(-)
diff --git a/rector.php b/rector.php
index 1d25ee45..51312e9f 100644
--- a/rector.php
+++ b/rector.php
@@ -12,6 +12,7 @@
])
// uncomment to reach your current PHP version
->withPhpSets()
- ->withTypeCoverageLevel(2)
+ ->withTypeCoverageLevel(3)
->withDeadCodeLevel(0)
- ->withCodeQualityLevel(1);
+ ->withCodeQualityLevel(1)
+;
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 915e2685..4bbca3b1 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -12,6 +12,7 @@
use Recruiter\Job;
use Recruiter\JobExecution;
use Recruiter\JobToSchedule;
+use Recruiter\RetryPolicy\DoNotDoItAgain;
use Recruiter\Workable;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Timeless as T;
@@ -439,7 +440,7 @@ private function aJobToSchedule($job = null)
return new JobToSchedule($job);
}
- private function workableMock()
+ private function workableMock(): MockObject&Workable
{
return $this
->getMockBuilder(Workable::class)
@@ -459,7 +460,7 @@ private function workableMockWithCustomParameters($parameters)
return $workable;
}
- private function jobExecutionMock($executionParameters)
+ private function jobExecutionMock(array $executionParameters): MockObject&JobExecution
{
$jobExecutionMock = $this
->getMockBuilder(JobExecution::class)
@@ -490,7 +491,7 @@ private function jobMockWithAttemptsAndCustomParameters(
'ended_at' => T\MongoDate::from($endedAt),
],
'retry_policy' => [
- 'class' => \Recruiter\RetryPolicy\DoNotDoItAgain::class,
+ 'class' => DoNotDoItAgain::class,
'parameters' => [],
],
];
diff --git a/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php b/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
index d9f3f966..0106c203 100644
--- a/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
+++ b/spec/Recruiter/RetryPolicy/ExponentialBackoffTest.php
@@ -2,6 +2,7 @@
namespace Recruiter\RetryPolicy;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Recruiter\JobAfterFailure;
use Timeless as T;
@@ -52,12 +53,12 @@ public function testCanBeCreatedByTargetingAMaximumInterval(): void
);
}
- private function jobExecutedFor($times)
+ private function jobExecutedFor(int $times): MockObject&JobAfterFailure
{
$job = $this->getMockBuilder(JobAfterFailure::class)->disableOriginalConstructor()->getMock();
$job->expects($this->any())
->method('numberOfAttempts')
- ->will($this->returnValue($times))
+ ->willReturn($times)
;
return $job;
diff --git a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
index 750063dc..732b3301 100644
--- a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
+++ b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
@@ -128,7 +128,7 @@ public function testRetriableExceptionsThatAreNotExceptions(): void
new RetriableExceptionFilter($retryPolicy, [$notAnExceptionClass]);
}
- private function jobFailedWithException($exception)
+ private function jobFailedWithException(\Throwable $exception): MockObject&JobAfterFailure
{
$jobAfterFailure = $this
->getMockBuilder(JobAfterFailure::class)
@@ -139,7 +139,7 @@ private function jobFailedWithException($exception)
$jobAfterFailure
->expects($this->any())
->method('causeOfFailure')
- ->will($this->returnValue($exception))
+ ->willReturn($exception)
;
return $jobAfterFailure;
diff --git a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
index 515a6e3f..9222c9f9 100644
--- a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
+++ b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
@@ -2,6 +2,7 @@
namespace Recruiter\RetryPolicy;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Recruiter\JobAfterFailure;
use Recruiter\RetryPolicy;
@@ -11,21 +12,19 @@ class SelectByExceptionTest extends TestCase
{
public function testCanBeBuilt(): void
{
- $retryPolicy = SelectByException::create()
- ->when(\InvalidArgumentException::class)->then(new DoNotDoItAgain())
- ->when(\LogicException::class)->then(new DoNotDoItAgain())
- ->build()
+ SelectByException::create()
+ ->when(\InvalidArgumentException::class)->then(new DoNotDoItAgain())
+ ->when(\LogicException::class)->then(new DoNotDoItAgain())
+ ->build()
;
-
- $this->assertInstanceOf(RetryPolicy::class, $retryPolicy);
}
public function testCanBeExportedAndImported(): void
{
$retryPolicy = SelectByException::create()
- ->when(\InvalidArgumentException::class)->then(new DoNotDoItAgain())
- ->when(\LogicException::class)->then(new DoNotDoItAgain())
- ->build()
+ ->when(\InvalidArgumentException::class)->then(new DoNotDoItAgain())
+ ->when(\LogicException::class)->then(new DoNotDoItAgain())
+ ->build()
;
$retryPolicyExported = $retryPolicy->export();
@@ -51,6 +50,9 @@ public function testSelectByException(): void
$retryPolicy->schedule($job);
}
+ /**
+ * @throws \Exception
+ */
public function testDefaultDoNotSchedule(): void
{
$exception = new \Exception('something');
@@ -65,12 +67,12 @@ public function testDefaultDoNotSchedule(): void
$retryPolicy->schedule($job);
}
- private function jobFailedWith(\Exception $exception)
+ private function jobFailedWith(\Throwable $exception): MockObject&JobAfterFailure
{
$job = $this->getMockBuilder(JobAfterFailure::class)->disableOriginalConstructor()->getMock();
$job->expects($this->any())
->method('causeOfFailure')
- ->will($this->returnValue($exception))
+ ->willReturn($exception)
;
return $job;
diff --git a/spec/Recruiter/RetryPolicy/TimeTableTest.php b/spec/Recruiter/RetryPolicy/TimeTableTest.php
index 4110e6a9..d2a8499d 100644
--- a/spec/Recruiter/RetryPolicy/TimeTableTest.php
+++ b/spec/Recruiter/RetryPolicy/TimeTableTest.php
@@ -2,6 +2,7 @@
namespace Recruiter\RetryPolicy;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Recruiter\Job;
use Recruiter\JobAfterFailure;
@@ -111,7 +112,7 @@ public function testInvalidTimeTableBecauseRescheduleTimeIsGreaterThanTimeWindow
$tt = new TimeTable(['1 minute ago' => '2 minutes']);
}
- private function givenJobThat(T\Moment $wasCreatedAt)
+ private function givenJobThat(T\Moment $wasCreatedAt): MockObject&JobAfterFailure
{
$job = $this->getMockBuilder(JobAfterFailure::class)
->disableOriginalConstructor()
@@ -126,7 +127,7 @@ private function givenJobThat(T\Moment $wasCreatedAt)
return $job;
}
- private function jobThatWasCreated(string $relativeTime): JobAfterFailure
+ private function jobThatWasCreated(string $relativeTime): MockObject&JobAfterFailure
{
$wasCreatedAt = T\Moment::fromTimestamp(strtotime($relativeTime));
$job = $this->getMockBuilder(JobAfterFailure::class)
diff --git a/spec/Recruiter/WorkerProcessTest.php b/spec/Recruiter/WorkerProcessTest.php
index 07a036b6..209ea21b 100644
--- a/spec/Recruiter/WorkerProcessTest.php
+++ b/spec/Recruiter/WorkerProcessTest.php
@@ -59,17 +59,17 @@ public function testDoNotRetireWorkerIfAlive(): void
$process->cleanUp($this->repository);
}
- private function givenWorkerProcessAlive()
+ private function givenWorkerProcessAlive(): MockObject&Process
{
return $this->givenWorkerProcess(true);
}
- private function givenWorkerProcessDead()
+ private function givenWorkerProcessDead(): MockObject&Process
{
return $this->givenWorkerProcess(false);
}
- private function givenWorkerProcess($alive)
+ private function givenWorkerProcess(bool $alive): MockObject&Process
{
$process = $this->getMockBuilder(Process::class)
->onlyMethods(['isAlive'])
@@ -79,7 +79,7 @@ private function givenWorkerProcess($alive)
$process->expects($this->any())
->method('isAlive')
- ->will($this->returnValue($alive))
+ ->willReturn($alive)
;
return $process;
From 6ed91571aad1180147039c53c06e83d570feab38 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 21:29:53 +0200
Subject: [PATCH 39/59] Increase rector level to 4
---
rector.php | 2 +-
...reCalledWhenWorkableImplementsFinalizerInterfaceTest.php | 2 +-
spec/Recruiter/Job/RepositoryTest.php | 6 +++---
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/rector.php b/rector.php
index 51312e9f..bfef9bcc 100644
--- a/rector.php
+++ b/rector.php
@@ -12,7 +12,7 @@
])
// uncomment to reach your current PHP version
->withPhpSets()
- ->withTypeCoverageLevel(3)
+ ->withTypeCoverageLevel(4)
->withDeadCodeLevel(0)
->withCodeQualityLevel(1)
;
diff --git a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
index daceaafb..a5891c64 100644
--- a/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
+++ b/spec/Recruiter/FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest.php
@@ -10,7 +10,7 @@
class FinalizerMethodsAreCalledWhenWorkableImplementsFinalizerInterfaceTest extends TestCase
{
private MockObject&Repository $repository;
- private EventDispatcherInterface $dispatcher;
+ private MockObject&EventDispatcherInterface $dispatcher;
private ListenerSpy $listener;
/**
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index 4bbca3b1..b5ddb718 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -24,7 +24,7 @@ class RepositoryTest extends TestCase
private Database $recruiterDb;
private Repository $repository;
private T\ClockInterface $clock;
- private EventDispatcherInterface $eventDispatcher;
+ private MockObject&EventDispatcherInterface $eventDispatcher;
/**
* @throws Exception
@@ -448,13 +448,13 @@ private function workableMock(): MockObject&Workable
;
}
- private function workableMockWithCustomParameters($parameters)
+ private function workableMockWithCustomParameters(array $parameters): MockObject&Workable
{
$workable = $this->workableMock();
$workable
->expects($this->any())
->method('export')
- ->will($this->returnValue($parameters))
+ ->willReturn($parameters)
;
return $workable;
From f19c94d35ea723e93d6c1773f448a267a0ab9506 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 21:35:53 +0200
Subject: [PATCH 40/59] Fix type hint
---
.../RetryPolicy/RetriableExceptionFilterTest.php | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
index 732b3301..f0767844 100644
--- a/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
+++ b/spec/Recruiter/RetryPolicy/RetriableExceptionFilterTest.php
@@ -2,6 +2,7 @@
namespace Recruiter\RetryPolicy;
+use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Recruiter\JobAfterFailure;
@@ -12,13 +13,16 @@ class RetriableExceptionFilterTest extends TestCase
private MockObject&RetryPolicy $filteredRetryPolicy;
/**
- * @throws \PHPUnit\Framework\MockObject\Exception
+ * @throws Exception
*/
protected function setUp(): void
{
$this->filteredRetryPolicy = $this->createMock(RetryPolicy::class);
}
+ /**
+ * @throws Exception
+ */
public function testCallScheduleOnRetriableException(): void
{
$exception = $this->createMock(\Exception::class);
@@ -128,7 +132,7 @@ public function testRetriableExceptionsThatAreNotExceptions(): void
new RetriableExceptionFilter($retryPolicy, [$notAnExceptionClass]);
}
- private function jobFailedWithException(\Throwable $exception): MockObject&JobAfterFailure
+ private function jobFailedWithException(mixed $exception): MockObject&JobAfterFailure
{
$jobAfterFailure = $this
->getMockBuilder(JobAfterFailure::class)
From 0f2727a0a469417e1652fd14eee252072f114afb Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 22:00:27 +0200
Subject: [PATCH 41/59] Increase PHPStan level to 2
---
phpstan.neon | 4 +-
spec/Recruiter/Job/RepositoryTest.php | 2 +-
spec/Recruiter/JobToScheduleTest.php | 1 +
.../Command/Bko/RemoveSchedulerCommand.php | 6 ++-
src/Recruiter/Job.php | 2 +-
src/Recruiter/JobToSchedule.php | 38 ++++++++++++++-----
src/Timeless/Clock.php | 12 ++++--
src/Timeless/ClockInterface.php | 4 +-
src/Timeless/StoppedClock.php | 12 ++++--
9 files changed, 56 insertions(+), 25 deletions(-)
diff --git a/phpstan.neon b/phpstan.neon
index 3bb2b042..2db8cff2 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,5 +1,5 @@
parameters:
- level: 1
+ level: 2
paths:
- src
- spec
@@ -9,5 +9,5 @@ parameters:
- '#Function recruiter_became_master not found.#'
- '#Function recruiter_stept_back not found.#'
- '#Unsafe usage of new static\(\).#'
- - '#Call to an undefined static method Sink\\BlackHole::whateverStaticMethod\(\).#'
+ - '#to an undefined .* Sink\\BlackHole#'
inferPrivatePropertyTypeFromConstructor: true
diff --git a/spec/Recruiter/Job/RepositoryTest.php b/spec/Recruiter/Job/RepositoryTest.php
index b5ddb718..547d5212 100644
--- a/spec/Recruiter/Job/RepositoryTest.php
+++ b/spec/Recruiter/Job/RepositoryTest.php
@@ -23,7 +23,7 @@ class RepositoryTest extends TestCase
{
private Database $recruiterDb;
private Repository $repository;
- private T\ClockInterface $clock;
+ private T\StoppedClock $clock;
private MockObject&EventDispatcherInterface $eventDispatcher;
/**
diff --git a/spec/Recruiter/JobToScheduleTest.php b/spec/Recruiter/JobToScheduleTest.php
index ce35099b..943ccbce 100644
--- a/spec/Recruiter/JobToScheduleTest.php
+++ b/spec/Recruiter/JobToScheduleTest.php
@@ -17,6 +17,7 @@ protected function setUp(): void
$this->job = $this
->getMockBuilder(Job::class)
->disableOriginalConstructor()
+ ->addMethods(['send'])
->getMock()
;
}
diff --git a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
index 29369c47..df3aa187 100644
--- a/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
+++ b/src/Recruiter/Infrastructure/Command/Bko/RemoveSchedulerCommand.php
@@ -9,6 +9,7 @@
use Recruiter\Infrastructure\Persistence\Mongodb\URI as MongoURI;
use Recruiter\Scheduler\Repository as SchedulerRepository;
use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
@@ -76,6 +77,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
private function selectUrnToDelete(array $urns, InputInterface $input, OutputInterface $output)
{
+ /** @var QuestionHelper $helper */
$helper = $this->getHelper('question');
$question = new ChoiceQuestion(
'Please select the scheduler which you want delete',
@@ -94,7 +96,7 @@ private function selectUrnToDelete(array $urns, InputInterface $input, OutputInt
return $selectedUrn;
}
- private function printTable(array $data, OutputInterface $output)
+ private function printTable(array $data, OutputInterface $output): void
{
$rows = [];
foreach ($data as $row) {
@@ -112,7 +114,7 @@ private function printTable(array $data, OutputInterface $output)
echo PHP_EOL;
}
- protected function buildOutputData()
+ protected function buildOutputData(): ?array
{
$outputData = [];
$i = 0;
diff --git a/src/Recruiter/Job.php b/src/Recruiter/Job.php
index b784650b..20083471 100644
--- a/src/Recruiter/Job.php
+++ b/src/Recruiter/Job.php
@@ -124,7 +124,7 @@ public function scheduledBy(string $namespace, string $id, int $executions)
return $this;
}
- public function methodToCallOnWorkable($method)
+ public function methodToCallOnWorkable($method): void
{
if (!method_exists($this->workable, $method)) {
throw new \Exception("Unknown method '$method' on workable instance");
diff --git a/src/Recruiter/JobToSchedule.php b/src/Recruiter/JobToSchedule.php
index cf260a7e..cbc48d98 100644
--- a/src/Recruiter/JobToSchedule.php
+++ b/src/Recruiter/JobToSchedule.php
@@ -7,22 +7,27 @@
use Timeless\Interval;
use Timeless\Moment;
+/**
+ * @method send() to make PHPStan happy in tests
+ */
class JobToSchedule
{
- /** @var bool */
- private $mustBeScheduled;
+ private bool $mustBeScheduled;
public function __construct(private readonly Job $job)
{
$this->mustBeScheduled = false;
}
- public function doNotRetry()
+ public function doNotRetry(): static
{
return $this->retryWithPolicy(new RetryPolicy\DoNotDoItAgain());
}
- public function retryManyTimes($howManyTimes, Interval $timeToWaitBeforeRetry, $retriableExceptionTypes = [])
+ /**
+ * @return $this
+ */
+ public function retryManyTimes($howManyTimes, Interval $timeToWaitBeforeRetry, $retriableExceptionTypes = []): static
{
$this->job->retryWithPolicy(
$this->filterForRetriableExceptions(
@@ -34,7 +39,10 @@ public function retryManyTimes($howManyTimes, Interval $timeToWaitBeforeRetry, $
return $this;
}
- public function retryWithPolicy(RetryPolicy $retryPolicy, $retriableExceptionTypes = [])
+ /**
+ * @return $this
+ */
+ public function retryWithPolicy(RetryPolicy $retryPolicy, $retriableExceptionTypes = []): static
{
$this->job->retryWithPolicy(
$this->filterForRetriableExceptions(
@@ -46,17 +54,26 @@ public function retryWithPolicy(RetryPolicy $retryPolicy, $retriableExceptionTyp
return $this;
}
- public function inBackground()
+ /**
+ * @return $this
+ */
+ public function inBackground(): static
{
return $this->scheduleAt(T\now());
}
- public function scheduleIn(Interval $duration)
+ /**
+ * @return $this
+ */
+ public function scheduleIn(Interval $duration): static
{
return $this->scheduleAt($duration->fromNow());
}
- public function scheduleAt(Moment $momentInTime)
+ /**
+ * @return $this
+ */
+ public function scheduleAt(Moment $momentInTime): static
{
$this->mustBeScheduled = true;
$this->job->scheduleAt($momentInTime);
@@ -115,7 +132,10 @@ private function emptyEventDispatcher(): EventDispatcher
return new EventDispatcher();
}
- public function __call($name, $arguments)
+ /**
+ * @throws \Exception
+ */
+ public function __call(string $name, array $arguments)
{
$this->job->methodToCallOnWorkable($name);
diff --git a/src/Timeless/Clock.php b/src/Timeless/Clock.php
index d046af0f..0c90fa27 100644
--- a/src/Timeless/Clock.php
+++ b/src/Timeless/Clock.php
@@ -4,14 +4,18 @@
class Clock implements ClockInterface
{
- public function start(): ClockInterface
+ public function start(): self
{
- return clock($this);
+ clock($this);
+
+ return $this;
}
- public function stop(): ClockInterface
+ public function stop(): StoppedClock
{
- return clock(new StoppedClock($this->now()));
+ clock($clock = new StoppedClock($this->now()));
+
+ return $clock;
}
public function now(): Moment
diff --git a/src/Timeless/ClockInterface.php b/src/Timeless/ClockInterface.php
index b5a365b8..65faa620 100644
--- a/src/Timeless/ClockInterface.php
+++ b/src/Timeless/ClockInterface.php
@@ -6,7 +6,7 @@ interface ClockInterface
{
public function now(): Moment;
- public function start(): ClockInterface;
+ public function start(): Clock;
- public function stop(): ClockInterface;
+ public function stop(): StoppedClock;
}
diff --git a/src/Timeless/StoppedClock.php b/src/Timeless/StoppedClock.php
index 77392ab4..5a82acd0 100644
--- a/src/Timeless/StoppedClock.php
+++ b/src/Timeless/StoppedClock.php
@@ -18,13 +18,17 @@ public function driftForwardBySeconds(int $seconds): void
$this->now = $this->now->after(seconds($seconds));
}
- public function start(): ClockInterface
+ public function start(): Clock
{
- return clock(new Clock());
+ clock($clock = new Clock());
+
+ return $clock;
}
- public function stop(): ClockInterface
+ public function stop(): self
{
- return clock($this);
+ clock($this);
+
+ return $this;
}
}
From 5f889bc750eb54afac56208ef4c3a5c816a3e7cc Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 22:11:48 +0200
Subject: [PATCH 42/59] Try to fix more test issues
---
spec/Recruiter/JobToScheduleTest.php | 11 +++---
src/Recruiter/Job.php | 19 +++++++---
src/Recruiter/Job/Repository.php | 57 +++++++++++++++-------------
3 files changed, 50 insertions(+), 37 deletions(-)
diff --git a/spec/Recruiter/JobToScheduleTest.php b/spec/Recruiter/JobToScheduleTest.php
index 943ccbce..be23900f 100644
--- a/spec/Recruiter/JobToScheduleTest.php
+++ b/spec/Recruiter/JobToScheduleTest.php
@@ -2,6 +2,7 @@
namespace Recruiter;
+use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Timeless as T;
@@ -11,15 +12,13 @@ class JobToScheduleTest extends TestCase
private T\ClockInterface $clock;
private MockObject&Job $job;
+ /**
+ * @throws Exception
+ */
protected function setUp(): void
{
$this->clock = T\clock()->stop();
- $this->job = $this
- ->getMockBuilder(Job::class)
- ->disableOriginalConstructor()
- ->addMethods(['send'])
- ->getMock()
- ;
+ $this->job = $this->createMock(Job::class);
}
protected function tearDown(): void
diff --git a/src/Recruiter/Job.php b/src/Recruiter/Job.php
index 20083471..ef8af24f 100644
--- a/src/Recruiter/Job.php
+++ b/src/Recruiter/Job.php
@@ -96,7 +96,10 @@ public function inGroup(array|string $group): static
return $this;
}
- public function scheduleAt(Moment $at)
+ /**
+ * @return $this
+ */
+ public function scheduleAt(Moment $at): static
{
$this->status['locked'] = false;
$this->status['scheduled_at'] = T\MongoDate::from($at);
@@ -104,14 +107,20 @@ public function scheduleAt(Moment $at)
return $this;
}
- public function withUrn(string $urn)
+ /**
+ * @return $this
+ */
+ public function withUrn(string $urn): static
{
$this->status['urn'] = $urn;
return $this;
}
- public function scheduledBy(string $namespace, string $id, int $executions)
+ /**
+ * @return $this
+ */
+ public function scheduledBy(string $namespace, string $id, int $executions): static
{
$this->status['scheduled'] = [
'by' => [
@@ -132,7 +141,7 @@ public function methodToCallOnWorkable($method): void
$this->status['workable']['method'] = $method;
}
- public function execute(EventDispatcherInterface $eventDispatcher)
+ public function execute(EventDispatcherInterface $eventDispatcher): JobExecution
{
$methodToCall = $this->status['workable']['method'];
try {
@@ -148,7 +157,7 @@ public function execute(EventDispatcherInterface $eventDispatcher)
return $this->lastJobExecution;
}
- public function retryStatistics()
+ public function retryStatistics(): array
{
return [
'job_id' => (string) $this->id(),
diff --git a/src/Recruiter/Job/Repository.php b/src/Recruiter/Job/Repository.php
index ef3dc499..d99fbe41 100644
--- a/src/Recruiter/Job/Repository.php
+++ b/src/Recruiter/Job/Repository.php
@@ -4,13 +4,15 @@
use MongoDB;
use MongoDB\BSON\ObjectId;
+use MongoDB\Collection;
+use MongoDB\Driver\CursorInterface;
use Recruiter\Job;
use Timeless as T;
class Repository
{
- private $scheduled;
- private $archived;
+ private Collection $scheduled;
+ private Collection $archived;
public function __construct(MongoDB\Database $db)
{
@@ -18,7 +20,7 @@ public function __construct(MongoDB\Database $db)
$this->archived = $db->selectCollection('archived');
}
- public function all()
+ public function all(): array
{
return $this->map(
$this->scheduled->find([], [
@@ -27,14 +29,14 @@ public function all()
);
}
- public function archiveAll()
+ public function archiveAll(): void
{
foreach ($this->all() as $job) {
$this->archive($job);
}
}
- public function scheduled($id)
+ public function scheduled(string|ObjectId $id): Job
{
if (is_string($id)) {
$id = new ObjectId($id);
@@ -49,7 +51,7 @@ public function scheduled($id)
return $found[0];
}
- public function archived($id)
+ public function archived(string|ObjectId $id): Job
{
if (is_string($id)) {
$id = new ObjectId($id);
@@ -64,7 +66,7 @@ public function archived($id)
return $found[0];
}
- public function save(Job $job)
+ public function save(Job $job): void
{
$document = $job->export();
$this->scheduled->replaceOne(
@@ -74,14 +76,14 @@ public function save(Job $job)
);
}
- public function archive(Job $job)
+ public function archive(Job $job): void
{
$document = $job->export();
$this->scheduled->deleteOne(['_id' => $document['_id']]);
$this->archived->replaceOne(['_id' => $document['_id']], $document, ['upsert' => true]);
}
- public function releaseAll($jobIds)
+ public function releaseAll($jobIds): int
{
$result = $this->scheduled->updateMany(
['_id' => ['$in' => $jobIds]],
@@ -93,10 +95,10 @@ public function releaseAll($jobIds)
public function countArchived(): int
{
- return $this->archived->count();
+ return $this->archived->countDocuments();
}
- public function cleanArchived(T\Moment $upperLimit)
+ public function cleanArchived(T\Moment $upperLimit): int
{
$documents = $this->archived->find(
[
@@ -116,7 +118,7 @@ public function cleanArchived(T\Moment $upperLimit)
return $deleted;
}
- public function cleanScheduled(T\Moment $upperLimit)
+ public function cleanScheduled(T\Moment $upperLimit): int
{
$result = $this->scheduled->deleteMany([
'created_at' => [
@@ -132,7 +134,7 @@ public function queued(
?T\Moment $at = null,
?T\Moment $from = null,
array $query = [],
- ) {
+ ): int {
if (null === $at) {
$at = T\now();
}
@@ -150,7 +152,7 @@ public function queued(
return $this->scheduled->count($query);
}
- public function postponed($group = null, ?T\Moment $at = null, array $query = [])
+ public function postponed($group = null, ?T\Moment $at = null, array $query = []): int
{
if (null === $at) {
$at = T\now();
@@ -162,19 +164,19 @@ public function postponed($group = null, ?T\Moment $at = null, array $query = []
$query['group'] = $group;
}
- return $this->scheduled->count($query);
+ return $this->scheduled->countDocuments($query);
}
- public function scheduledCount($group = null, array $query = [])
+ public function scheduledCount($group = null, array $query = []): int
{
if (null !== $group) {
$query['group'] = $group;
}
- return $this->scheduled->count($query);
+ return $this->scheduled->countDocuments($query);
}
- public function queuedGroupedBy($field, array $query = [], $group = null)
+ public function queuedGroupedBy($field, array $query = [], $group = null): array
{
$query['scheduled_at']['$lte'] = T\MongoDate::from(T\now());
if (null !== $group) {
@@ -197,7 +199,7 @@ public function queuedGroupedBy($field, array $query = [], $group = null)
return $distinctAndCount;
}
- public function recentHistory($group = null, ?T\Moment $at = null, array $query = [])
+ public function recentHistory($group = null, ?T\Moment $at = null, array $query = []): array
{
if (null === $at) {
$at = T\now();
@@ -305,7 +307,7 @@ public function countDelayedScheduledJobs(T\Moment $lowerLimit): int
]);
}
- public function delayedScheduledJobs(T\Moment $lowerLimit)
+ public function delayedScheduledJobs(T\Moment $lowerLimit): array
{
return $this->map(
$this->scheduled->find([
@@ -319,7 +321,7 @@ public function delayedScheduledJobs(T\Moment $lowerLimit)
public function recentJobsWithManyAttempts(
T\Moment $lowerLimit,
T\Moment $upperLimit,
- ) {
+ ): array {
$archived = $this->map(
$this->recentArchivedOrScheduledJobsWithManyAttempts(
$lowerLimit,
@@ -342,7 +344,7 @@ public function slowRecentJobs(
T\Moment $lowerLimit,
T\Moment $upperLimit,
$secondsToConsiderJobAsSlow = 5,
- ) {
+ ): array {
$archived = [];
$archivedArray = $this->slowArchivedRecentJobs(
$lowerLimit,
@@ -369,7 +371,7 @@ private function slowArchivedRecentJobs(
T\Moment $lowerLimit,
T\Moment $upperLimit,
$secondsToConsiderJobAsSlow,
- ) {
+ ): array {
return $this->archived->aggregate([
[
'$match' => [
@@ -413,7 +415,7 @@ private function slowScheduledRecentJobs(
T\Moment $lowerLimit,
T\Moment $upperLimit,
$secondsToConsiderJobAsSlow,
- ) {
+ ): array {
return $this->scheduled->aggregate([
[
'$match' => [
@@ -464,7 +466,7 @@ private function countRecentArchivedOrScheduledJobsWithManyAttempts(
T\Moment $lowerLimit,
T\Moment $upperLimit,
$collectionName,
- ) {
+ ): int {
return count($this->recentArchivedOrScheduledJobsWithManyAttempts(
$lowerLimit,
$upperLimit,
@@ -488,7 +490,10 @@ private function recentArchivedOrScheduledJobsWithManyAttempts(
]);
}
- private function map($cursor)
+ /**
+ * @return array
+ */
+ private function map(CursorInterface $cursor): array
{
$jobs = [];
foreach ($cursor as $document) {
From ab26e18b7677df9d424d50fa4beab47eaa923951 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Sun, 3 Aug 2025 23:55:36 +0200
Subject: [PATCH 43/59] Bump dependencies
---
composer.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/composer.json b/composer.json
index 1fd7cb23..1b7cb6eb 100644
--- a/composer.json
+++ b/composer.json
@@ -35,8 +35,8 @@
"mongodb/mongodb": "^2.1",
"monolog/monolog": "^3.9",
"psr/log": "^3.0",
- "recruiterphp/concurrency": "^4.0",
- "recruiterphp/geezer": "^6.0",
+ "recruiterphp/concurrency": "^5.0",
+ "recruiterphp/geezer": "^7.0",
"symfony/console": "^7.3",
"symfony/event-dispatcher": "^7.3",
"ulrichsg/getopt-php": "^4.0"
From 2726f1e35b53ac4d4c5502f975df8b71e4572135 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 00:15:35 +0200
Subject: [PATCH 44/59] Implement minor improvements
---
spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php | 4 ++--
spec/Recruiter/Acceptance/FaultToleranceTest.php | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
index 11ec14dd..244b10ac 100644
--- a/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
+++ b/spec/Recruiter/Acceptance/BaseAcceptanceTestCase.php
@@ -166,7 +166,7 @@ protected function startWorker(array $additionalOptions = [])
return end($this->processWorkers);
}
- protected function stopProcessWithSignal(array $processAndPipes, $signal): void
+ protected function stopProcessWithSignal(array $processAndPipes, int $signal): void
{
[$process, $pipes, $name] = $processAndPipes;
proc_terminate($process, $signal);
@@ -183,7 +183,7 @@ protected function stopProcessWithSignal(array $processAndPipes, $signal): void
/**
* @param int $duration milliseconds
*/
- protected function enqueueJob($duration = 10, $tag = 'generic'): void
+ protected function enqueueJob(int $duration = 10, $tag = 'generic'): void
{
$workable = ShellCommand::fromCommandLine('sleep ' . ($duration / 1000));
$workable
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index 6c1140c7..89096f06 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -81,7 +81,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies(): void
$worker = $this->startWorker();
$this->waitForNumberOfWorkersToBe(1);
[$assignments, $_] = $this->recruiter->assignJobsToWorkers();
- $this->assertEquals(1, count($assignments));
+ $this->assertCount(1, $assignments);
sleep(2);
// The worker is dead and the job is not properly scheduled
$this->recruiter->retireDeadWorkers(new \DateTimeImmutable(), T\seconds(0));
@@ -92,7 +92,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies(): void
$this->waitForNumberOfWorkersToBe(1);
// Here the job is assigned and rescheduled by the retry policy because found crashed
[$assignments, $_] = $this->recruiter->assignJobsToWorkers();
- $this->assertEquals(1, count($assignments));
+ $this->assertCount(1, $assignments);
sleep(2);
// The worker is dead and the job is not properly scheduled
$this->recruiter->retireDeadWorkers(new \DateTimeImmutable(), T\seconds(0));
@@ -112,10 +112,10 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies(): void
$this->assertEquals(0, $this->recruiter->queued());
}
- private function assertJobIsMarkedAsCrashed()
+ private function assertJobIsMarkedAsCrashed(): void
{
$jobs = iterator_to_array($this->recruiterDb->selectCollection('scheduled')->find());
- $this->assertEquals(1, count($jobs));
+ $this->assertCount(1, $jobs);
foreach ($jobs as $job) {
$this->assertArrayHasKey('last_execution', $job);
$this->assertArrayHasKey('crashed', $job['last_execution']);
From 28a1b6d0fe0c9459c5011ea77ee7b644506f0d87 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 00:16:26 +0200
Subject: [PATCH 45/59] Add var dumper
---
composer.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 1b7cb6eb..3953b885 100644
--- a/composer.json
+++ b/composer.json
@@ -49,7 +49,8 @@
"giorgiosironi/eris": "^1.0",
"phpstan/phpstan": "*",
"phpunit/phpunit": "^10.0",
- "rector/rector": "^2.1"
+ "rector/rector": "^2.1",
+ "symfony/var-dumper": "^7.3"
},
"suggest": {
"symfony/console": "In order to use Recruiter\\Command\\RecruiterJobCommand."
From ec0a47033ae2da04c8e59c0700b339fed95ed5d1 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 00:20:45 +0200
Subject: [PATCH 46/59] Fixed the main Recruiter issue
---
examples/bootstrap.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/bootstrap.php b/examples/bootstrap.php
index bbc2269c..1911e47f 100644
--- a/examples/bootstrap.php
+++ b/examples/bootstrap.php
@@ -4,7 +4,7 @@
echo 'BOOTSTRAP!!!' . PHP_EOL;
-global $recruiter;
+assert(isset($recruiter));
assert($recruiter instanceof Recruiter);
$recruiter->getEventDispatcher()->addListener('job.failure.last', function ($event): void {
From 529ca764a1a2b614c4d21db60197bd37ad3f7392 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 00:23:29 +0200
Subject: [PATCH 47/59] Remove risky warning
---
spec/Recruiter/RetryPolicy/SelectByExceptionTest.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
index 9222c9f9..26ef5e9d 100644
--- a/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
+++ b/spec/Recruiter/RetryPolicy/SelectByExceptionTest.php
@@ -5,7 +5,6 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Recruiter\JobAfterFailure;
-use Recruiter\RetryPolicy;
use Timeless as T;
class SelectByExceptionTest extends TestCase
@@ -17,6 +16,8 @@ public function testCanBeBuilt(): void
->when(\LogicException::class)->then(new DoNotDoItAgain())
->build()
;
+
+ $this->expectNotToPerformAssertions();
}
public function testCanBeExportedAndImported(): void
From 7911175f9ec300887867a3c1f38d9ff3a3e90f63 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 00:37:13 +0200
Subject: [PATCH 48/59] Fix the issue with the exit
But tests are still flaky
---
spec/Recruiter/Acceptance/FaultToleranceTest.php | 4 ++--
...rGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php | 4 ++--
.../Workable/{ThrowsFatalError.php => ExitsAbruptly.php} | 5 ++---
3 files changed, 6 insertions(+), 7 deletions(-)
rename src/Recruiter/Workable/{ThrowsFatalError.php => ExitsAbruptly.php} (58%)
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index 89096f06..15d5befe 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -5,7 +5,7 @@
use Recruiter\Infrastructure\Memory\MemoryLimit;
use Recruiter\RetryPolicy\RetryManyTimes;
use Recruiter\Workable\FailsInConstructor;
-use Recruiter\Workable\ThrowsFatalError;
+use Recruiter\Workable\ExitsAbruptly;
use Timeless as T;
class FaultToleranceTest extends BaseAcceptanceTestCase
@@ -63,7 +63,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies(): void
// executions. The problem is that the retry policy is
// evaluated after the execution but fatal errors are not
// catchable and so the job will stay scheduled forever
- new ThrowsFatalError()
+ new ExitsAbruptly()
->asJobOf($this->recruiter)
->inBackground()
->retryWithPolicy(RetryManyTimes::forTimes(1, 0))
diff --git a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
index 5070e67b..e683558b 100644
--- a/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
+++ b/spec/Recruiter/Acceptance/WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest.php
@@ -2,7 +2,7 @@
namespace Recruiter\Acceptance;
-use Recruiter\Workable\ThrowsFatalError;
+use Recruiter\Workable\ExitsAbruptly;
class WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest extends BaseAcceptanceTestCase
{
@@ -11,7 +11,7 @@ class WorkerGuaranteedToExitWithFailureCodeInCaseOfExceptionTest extends BaseAcc
*/
public function testInCaseOfExceptionTheExitCodeOfWorkerProcessIsNotZero(): void
{
- new ThrowsFatalError()
+ new ExitsAbruptly()
->asJobOf($this->recruiter)
->inBackground()
->execute()
diff --git a/src/Recruiter/Workable/ThrowsFatalError.php b/src/Recruiter/Workable/ExitsAbruptly.php
similarity index 58%
rename from src/Recruiter/Workable/ThrowsFatalError.php
rename to src/Recruiter/Workable/ExitsAbruptly.php
index e86b0996..dd3e5876 100644
--- a/src/Recruiter/Workable/ThrowsFatalError.php
+++ b/src/Recruiter/Workable/ExitsAbruptly.php
@@ -5,13 +5,12 @@
use Recruiter\Workable;
use Recruiter\WorkableBehaviour;
-class ThrowsFatalError implements Workable
+class ExitsAbruptly implements Workable
{
use WorkableBehaviour;
public function execute(): void
{
- /** @phpstan-ignore-next-line */
- new ThisClassDoesnNotExists();
+ exit(-1);
}
}
From dc95a28176f38564c0a7ac54054e939c731ba38f Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 00:37:27 +0200
Subject: [PATCH 49/59] Improve assertions
---
spec/Recruiter/Acceptance/FaultToleranceTest.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index 15d5befe..be41fb5a 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -18,7 +18,7 @@ public function testRecruiterCrashAfterLockingJobsBeforeAssignmentAndIsRestarted
$this->recruiter->bookJobsForWorkers();
$this->recruiter->rollbackLockedJobs();
[$assignments, $totalNumber] = $this->recruiter->assignJobsToWorkers();
- $this->assertEquals(1, count($assignments));
+ $this->assertCount(1, $assignments);
$this->assertEquals(1, $totalNumber);
}
@@ -35,7 +35,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor(): v
$this->waitForNumberOfWorkersToBe(1);
[$assignments, $_] = $this->recruiter->assignJobsToWorkers();
- $this->assertEquals(1, count($assignments));
+ $this->assertCount(1, $assignments);
sleep(2);
$jobDocument = current($this->scheduled->find()->toArray());
$this->assertEquals(1, $jobDocument['attempts']);
@@ -44,7 +44,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor(): v
$this->assertStringContainsString('I am supposed to fail in constructor code for testing purpose', $jobDocument['last_execution']['message']);
[$assignments, $_] = $this->recruiter->assignJobsToWorkers();
- $this->assertEquals(1, count($assignments));
+ $this->assertCount(1, $assignments);
sleep(2);
$jobDocument = current($this->archived->find()->toArray());
$this->assertEquals(2, $jobDocument['attempts']);
@@ -53,7 +53,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor(): v
$this->assertStringContainsString('I am supposed to fail in constructor code for testing purpose', $jobDocument['last_execution']['message']);
[$assignments, $_] = $this->recruiter->assignJobsToWorkers();
- $this->assertEquals(0, count($assignments));
+ $this->assertCount(0, $assignments);
}
public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies(): void
@@ -106,7 +106,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies(): void
// because found crashed and because it has been already
// executed 2 times
[$assignments, $_] = $this->recruiter->assignJobsToWorkers();
- $this->assertEquals(1, count($assignments));
+ $this->assertCount(1, $assignments);
sleep(1);
// The worker is not dead and the job is not scheduled anymore
$this->assertEquals(0, $this->recruiter->queued());
From c4431e7f6ad926df6919416c4506a7d6b75f9660 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 00:38:58 +0200
Subject: [PATCH 50/59] Increase waiting time
---
spec/Recruiter/Acceptance/FaultToleranceTest.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index be41fb5a..066d015e 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -96,7 +96,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDies(): void
sleep(2);
// The worker is dead and the job is not properly scheduled
$this->recruiter->retireDeadWorkers(new \DateTimeImmutable(), T\seconds(0));
- $this->waitForNumberOfWorkersToBe(0);
+ $this->waitForNumberOfWorkersToBe(0, 2);
$this->assertJobIsMarkedAsCrashed();
// Third execution of the job
From 2472cca244e93aa19ae520c3930d3feb9aa7acd2 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 09:22:38 +0200
Subject: [PATCH 51/59] Increase timeout
---
spec/Recruiter/Acceptance/FaultToleranceTest.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index 066d015e..57b66207 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -32,7 +32,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor(): v
;
$worker = $this->startWorker();
- $this->waitForNumberOfWorkersToBe(1);
+ $this->waitForNumberOfWorkersToBe(1, 2);
[$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertCount(1, $assignments);
From 183833a8a6b252d91b51e98c13f4fad7b37df9d2 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 09:29:15 +0200
Subject: [PATCH 52/59] Further increase timeout for pipeline
---
spec/Recruiter/Acceptance/FaultToleranceTest.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/Recruiter/Acceptance/FaultToleranceTest.php b/spec/Recruiter/Acceptance/FaultToleranceTest.php
index 57b66207..0faeb0b8 100644
--- a/spec/Recruiter/Acceptance/FaultToleranceTest.php
+++ b/spec/Recruiter/Acceptance/FaultToleranceTest.php
@@ -32,7 +32,7 @@ public function testRetryPolicyMustBeAppliedEvenWhenWorkerDiesInConstructor(): v
;
$worker = $this->startWorker();
- $this->waitForNumberOfWorkersToBe(1, 2);
+ $this->waitForNumberOfWorkersToBe(1, 5);
[$assignments, $_] = $this->recruiter->assignJobsToWorkers();
$this->assertCount(1, $assignments);
From 0e4fc2ff101aa8f10875d611b2a78afba7dc8727 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 10:54:01 +0200
Subject: [PATCH 53/59] Enhance CI pipeline
---
.github/workflows/ci.yml | 70 +++++++++++++++++++++++++++++++++++
.github/workflows/phpunit.yml | 41 --------------------
2 files changed, 70 insertions(+), 41 deletions(-)
create mode 100644 .github/workflows/ci.yml
delete mode 100644 .github/workflows/phpunit.yml
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..da778eea
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,70 @@
+name: CI Pipeline
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+permissions:
+ contents: read
+
+jobs:
+ setup:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Validate composer.json and composer.lock
+ run: composer validate --strict
+
+ - name: Cache Composer packages
+ id: composer-cache
+ uses: actions/cache@v3
+ with:
+ path: vendor
+ key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-php-
+
+ - name: Build with cache
+ run: |
+ docker buildx create --use
+ DOCKER_BUILDKIT=1 docker compose build --build-arg BUILDKIT_INLINE_CACHE=1
+
+ - name: Install dependencies
+ run: make install
+
+ test-fast:
+ needs: setup
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ - name: Restore cache and build
+ run: |
+ docker buildx create --use
+ DOCKER_BUILDKIT=1 docker compose build --build-arg BUILDKIT_INLINE_CACHE=1
+ make install
+ - name: Run fast tests
+ run: make test
+
+ test-long:
+ needs: setup
+ runs-on: ubuntu-latest
+ timeout-minutes: 90
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ - name: Restore cache and build
+ run: |
+ docker buildx create --use
+ DOCKER_BUILDKIT=1 docker compose build --build-arg BUILDKIT_INLINE_CACHE=1
+ make install
+ - name: Run long tests
+ run: make test-long
diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
deleted file mode 100644
index 9619b698..00000000
--- a/.github/workflows/phpunit.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-name: PHPUnit Tests
-
-on:
- push:
- branches: [ "master" ]
- pull_request:
- branches: [ "master" ]
-
-permissions:
- contents: read
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
-
- - name: Validate composer.json and composer.lock
- run: composer validate --strict
-
- - name: Cache Composer packages
- id: composer-cache
- uses: actions/cache@v3
- with:
- path: vendor
- key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
- restore-keys: |
- ${{ runner.os }}-php-
-
- - name: Build the Docker image
- run: make build
-
- - name: Install dependencies
- run: make install
-
- - name: Run test suite (except long ones)
- run: make test
-
- - name: Run test suite (only long ones)
- run: make test-long
From ba121ebb246482ee334587cf2da03cae79034480 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 12:15:14 +0200
Subject: [PATCH 54/59] Make long tests optional
---
.github/workflows/ci.yml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index da778eea..5262d402 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,6 +5,13 @@ on:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
+ workflow_dispatch:
+ inputs:
+ run_long_tests:
+ description: 'Run long tests'
+ required: false
+ default: false
+ type: boolean
permissions:
contents: read
@@ -57,6 +64,7 @@ jobs:
needs: setup
runs-on: ubuntu-latest
timeout-minutes: 90
+ if: github.event.inputs.run_long_tests == 'true'
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
From 914b265363d4d7ca621d49df2c5414e42eed6451 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 12:26:18 +0200
Subject: [PATCH 55/59] Use multistage build
---
Dockerfile | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index 1904a3f9..2f486df5 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM php:8.4-cli
+FROM php:8.4-cli AS base
# Install system dependencies
RUN apt-get update && apt-get install -y \
@@ -24,6 +24,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /app
+FROM base AS code
+
+# Set environment variable for Composer
+ENV COMPOSER_ALLOW_SUPERUSER=1
+
# Copy composer files
COPY composer.json composer.lock* ./
@@ -33,7 +38,4 @@ RUN composer install --optimize-autoloader
# Copy application code
COPY . .
-# Set environment variable for Composer
-ENV COMPOSER_ALLOW_SUPERUSER=1
-
CMD ["tail", "-f", "/dev/null"]
From e5818ec1a738b28263351dffae26f8381dd878d4 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 12:30:08 +0200
Subject: [PATCH 56/59] Improve the build process
---
.github/workflows/ci.yml | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5262d402..3d43092a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -40,7 +40,12 @@ jobs:
- name: Build with cache
run: |
docker buildx create --use
- DOCKER_BUILDKIT=1 docker compose build --build-arg BUILDKIT_INLINE_CACHE=1
+ docker buildx build \
+ --cache-from type=gha \
+ --cache-to type=gha,mode=max \
+ --load \
+ --tag recruiter-php \
+ .
- name: Install dependencies
run: make install
@@ -55,7 +60,11 @@ jobs:
- name: Restore cache and build
run: |
docker buildx create --use
- DOCKER_BUILDKIT=1 docker compose build --build-arg BUILDKIT_INLINE_CACHE=1
+ docker buildx build \
+ --cache-from type=gha \
+ --load \
+ --tag recruiter-php \
+ .
make install
- name: Run fast tests
run: make test
@@ -72,7 +81,11 @@ jobs:
- name: Restore cache and build
run: |
docker buildx create --use
- DOCKER_BUILDKIT=1 docker compose build --build-arg BUILDKIT_INLINE_CACHE=1
+ docker buildx build \
+ --cache-from type=gha \
+ --load \
+ --tag recruiter-php \
+ .
make install
- name: Run long tests
run: make test-long
From 45633c5c3bcaeeee7bfe10e9d549bc4667a130c1 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 13:02:19 +0200
Subject: [PATCH 57/59] Dependencies are already in build
---
.github/workflows/ci.yml | 5 -----
1 file changed, 5 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3d43092a..dc89e62a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -47,9 +47,6 @@ jobs:
--tag recruiter-php \
.
- - name: Install dependencies
- run: make install
-
test-fast:
needs: setup
runs-on: ubuntu-latest
@@ -65,7 +62,6 @@ jobs:
--load \
--tag recruiter-php \
.
- make install
- name: Run fast tests
run: make test
@@ -86,6 +82,5 @@ jobs:
--load \
--tag recruiter-php \
.
- make install
- name: Run long tests
run: make test-long
From 4070bafe7c50ad01a62af70572815ae06959c71a Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 21:58:00 +0200
Subject: [PATCH 58/59] Move volumes to ovverride
---
.env | 1 +
compose.dev.yaml | 4 ++++
compose.yaml | 2 --
3 files changed, 5 insertions(+), 2 deletions(-)
create mode 100644 .env
create mode 100644 compose.dev.yaml
diff --git a/.env b/.env
new file mode 100644
index 00000000..949df516
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+COMPOSE_FILE=compose.yaml:compose.dev.yaml
diff --git a/compose.dev.yaml b/compose.dev.yaml
new file mode 100644
index 00000000..e985c6b9
--- /dev/null
+++ b/compose.dev.yaml
@@ -0,0 +1,4 @@
+services:
+ php:
+ volumes:
+ - .:/app
diff --git a/compose.yaml b/compose.yaml
index 61c32cee..e0724f21 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -2,8 +2,6 @@ services:
php:
build: .
working_dir: /app
- volumes:
- - .:/app
environment:
- COMPOSER_ALLOW_SUPERUSER=1
- MONGODB_URI=mongodb://mongodb:27017/recruiter
From 18b1d3e9d3adeb251ec4537846588a89d9e27940 Mon Sep 17 00:00:00 2001
From: Davide Bellettini <325358+dbellettini@users.noreply.github.com>
Date: Mon, 4 Aug 2025 22:33:46 +0200
Subject: [PATCH 59/59] Add env to GitHub Actions
---
.github/workflows/ci.yml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dc89e62a..68c86bf2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -50,6 +50,8 @@ jobs:
test-fast:
needs: setup
runs-on: ubuntu-latest
+ env:
+ COMPOSE_FILE: compose.yaml
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
@@ -70,6 +72,8 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 90
if: github.event.inputs.run_long_tests == 'true'
+ env:
+ COMPOSE_FILE: compose.yaml
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx