From 585a8bf71a1dd03fe3b50f891513ecafd232609a Mon Sep 17 00:00:00 2001 From: Peter van der Wal Date: Wed, 10 Mar 2021 18:40:43 +0100 Subject: [PATCH 1/4] Fix concurrency issue in QueueManager::processBatch Error: Uncaught Amp\Beanstalk\DeadlineSoonException causing the ESB to crash Caused by: Wrong Beanstalk job deleted at the end of the job Caused by: Multiple Beanstalk jobs for the same job UUID. With multiple concurrent workers that same job UUID will be assigned to multiple workers. $uuidToBeanstalkIdMap[$job->getUuid()] will then only contain one of the beanstalk job ids, so one of the worker's queue manager won't be able to delete his job after finish. Caused by: Concurrent calls to QueueManager::processBatch() were possible (and should be possible), but the batch itself was shared over multiple HTTP requests. Causing the same job being inserted twice (or more). Resolved by: Processing the batch via a local variable instead of the shared property. --- src/Service/QueueManager.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Service/QueueManager.php b/src/Service/QueueManager.php index 505934e..b90ce29 100644 --- a/src/Service/QueueManager.php +++ b/src/Service/QueueManager.php @@ -223,9 +223,16 @@ private function jobExists(string $jobUuid): Promise private function processBatch(): \Generator { $this->logger->debug('Processing batch'); - yield $this->elasticSearch->bulkIndexJobs($this->batch, $this->flowConfig->getTube()); - foreach ($this->batch as $singleJob) { + // Store batch in a local variable and clear the shared property. Any other Producer instance may update and + // process $this->batch during a yield call within this method (emulating concurrency). This shouldn't cause + // duplicate inserts of the same job. + $batch = $this->batch; + $this->batch = []; + + yield $this->elasticSearch->bulkIndexJobs($batch, $this->flowConfig->getTube()); + + foreach ($batch as $singleJob) { yield $this->beanstalkClient->put( $singleJob->getUuid(), $singleJob->getTimeout(), @@ -233,8 +240,6 @@ private function processBatch(): \Generator $singleJob->getPriority() ); } - - $this->batch = []; } /** From 4dac59bd436fb7e5e0cbc63a3d9f48516c4a277a Mon Sep 17 00:00:00 2001 From: Peter van der Wal Date: Fri, 30 Oct 2020 11:28:19 +0100 Subject: [PATCH 2/4] Fix Travis CI composer version The Combination PHP <7.4 and maglnet/composer-require-checker doesn't work with Composer 2. User Composer version 1 for PHP 7.2 and 7.3. --- .travis.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 680e571..c064a3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,20 @@ sudo: required language: php -php: - - 7.2 - - 7.3 - - 7.4 + +jobs: + include: + # Combination PHP <7.4 and maglnet/composer-require-checker doesn't work with Composer 2 + - php: 7.2 + env: COMPOSER_VERSION=1.10.16 + - php: 7.3 + env: COMPOSER_VERSION=1.10.16 + - php: 7.4 + env: COMPOSER_VERSION=--stable env: - - ESB_CONSOLE_PORT=8080 ESB_HTTP_SERVER_PORT=34981 ESB_BEANSTALKD_URL=tcp://127.0.0.1:11300 ES_BASE_URI=http://127.0.0.1:9200 + global: + - ESB_CONSOLE_PORT=8080 ESB_HTTP_SERVER_PORT=34981 ESB_BEANSTALKD_URL=tcp://127.0.0.1:11300 ES_BASE_URI=http://127.0.0.1:9200 cache: directories: @@ -24,6 +31,8 @@ before_install: - echo -e '-Ddiscovery.type=single-node\n-XX:+DisableExplicitGC\n-Djdk.io.permissionsUseCanonicalPath=true\n-Dlog4j.skipJansi=true\n-server\n' | sudo tee -a /etc/elasticsearch/jvm.options - sudo chown -R elasticsearch:elasticsearch /etc/default/elasticsearch - sudo systemctl start elasticsearch + - composer --verbose self-update $COMPOSER_VERSION + - composer --version install: - sudo apt-get update @@ -31,7 +40,7 @@ install: before_script: - composer install - - composer global require maglnet/composer-require-checker && $HOME/.composer/vendor/bin/composer-require-checker --config-file=composer-require-checker.json; + - composer global require maglnet/composer-require-checker && $(composer config home)/vendor/bin/composer-require-checker --config-file=composer-require-checker.json; - vendor/bin/ecs check - vendor/bin/phpstan analyse --no-progress -l max -c phpstan.neon src/ From a2e5baf77a7f9480892389154b73fecc34024512 Mon Sep 17 00:00:00 2001 From: Peter van der Wal Date: Tue, 23 Feb 2021 11:40:04 +0100 Subject: [PATCH 3/4] Limit ECS and PhpStan versions Newer versions causing errors: ECS >= 8.3: PHP Fatal error: Uncaught OutOfBoundsException: Package "symplify/easy-coding-standard" is not installed in phar:///home/youwe/Projects/webgriffe-esb/vendor/phpstan/phpstan/phpstan.phar/vendor/composer/InstalledVersions.php:1081 PhpStan >= 0.12.67: Ignored error pattern /Unable to resolve the template type .*? in call to function Amp\\call/ was not matched in reported errors. Ignored error pattern /Unable to resolve the template type .*? in instantiation of class Amp\\Producer/ was not matched in reported errors. --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f4721fb..8ab1a28 100644 --- a/composer.json +++ b/composer.json @@ -56,8 +56,8 @@ "pda/pheanstalk": "^3.1", "mikey179/vfsstream": "^1.6", "amphp/artax": "^3.0", - "phpstan/phpstan": "^0.12", - "symplify/easy-coding-standard-prefixed": "^8.1" + "phpstan/phpstan": "^0.12 <=0.12.66", + "symplify/easy-coding-standard-prefixed": "^8.1 <8.3" }, "scripts": { "phpcs": "phpcs", From 9aecb43835b4aa6a5cdcc5540fc31a6739a34b9d Mon Sep 17 00:00:00 2001 From: Peter van der Wal Date: Tue, 23 Feb 2021 11:41:12 +0100 Subject: [PATCH 4/4] Typehint JobNotFoundException::__construct($code) PhpStan: Method Webgriffe\Esb\Exception\ElasticSearch\JobNotFoundException::__construct() has parameter $code with no typehint specified. --- src/Exception/ElasticSearch/JobNotFoundException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Exception/ElasticSearch/JobNotFoundException.php b/src/Exception/ElasticSearch/JobNotFoundException.php index f1f16ff..7566146 100644 --- a/src/Exception/ElasticSearch/JobNotFoundException.php +++ b/src/Exception/ElasticSearch/JobNotFoundException.php @@ -8,7 +8,7 @@ class JobNotFoundException extends \RuntimeException { - public function __construct(string $jobUuid, $code = 0, Throwable $previous = null) + public function __construct(string $jobUuid, int $code = 0, Throwable $previous = null) { parent::__construct(sprintf('Job with UUID "%s" has not been found.', $jobUuid), $code, $previous); }