The goal of this repository is to help reproduce an issue with using elasticsearch client inside phpunit tests in php 7.4.28 runtime at MacOS operating system.
First step is to install nix.
Following command will initialize docker containers and let them run in background.
cp docker-compose.yaml.dist docker-compose.yaml
docker-compose up -d
Open your terminal app and type following command in the repository root:
nix-shell
This will initialize nix shell with all required software dependencies like php, composer etc.
Install all code dependencies
composer install
Create ES Index
bin/init
Failing test is basically doing 3 steps:
- index document
- get document
- delete all documents in index
2.5k times, where each step is a standalone test (data provider is yielding next documents)
vendor/bin/phpunit tests/NixPHPUnitEs/FailingTest.php --testdox --verbose
In my case, it starts failing around 339 iteration with following error:
✘ Es with data set #339 [1001.98 ms]
│
│ Elasticsearch\Common\Exceptions\Curl\OperationTimeoutException: cURL error 28: Connection timeout after 1000 ms
│
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/Connection.php:584
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/Connection.php:274
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/react/promise/src/FulfilledPromise.php:28
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/ezimuel/ringphp/src/Future/CompletedFutureValue.php:55
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/ezimuel/ringphp/src/Core.php:341
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/Connection.php:345
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/Connection.php:241
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Transport.php:110
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Client.php:1929
│ /Users/xxx/Workspace/nix-phpunit-es/vendor/elasticsearch/elasticsearch/src/Elasticsearch/Client.php:911
│ /Users/xxx/Workspace/nix-phpunit-es/tests/NixPHPUnitEs/FailingTest.php:34
│ phpvfscomposer:///Users/xxx/Workspace/nix-phpunit-es/vendor/phpunit/phpunit/phpunit:97
│
Just to confirm that the issue has nothing to do with ES itself, here is passing test:
Passing test is doing exactly same thing, 10k times, but there is no generator used, everything happens in a single, 10k iterations loop.
vendor/bin/phpunit tests/NixPHPUnitEs/PassingTest.php --testdox --verbose
This behavior is probably more related to macOS libcurl than php itself as suggested here
There are two solutions to make Failingtest work:
- set curl option
CURLOPT_FORBID_REUSE => true
documentation - use custom CurlHandler
ClientBuilder::create()->setHandler(new CurlHandler(['max_handles' => 0]))
for the elasticsearch client.
I'm still not sure what is the root cuase for this behavior and why on Linux everything works out of the box.
Below some findings:
This issue does not exist at PHP installed at Ubuntu 20.04 (and probably other distros)
If we force trigger curl_close (by calling destructor on curl handler) tests are passing regardless of the number of iterations
Elasticsearch seems to not be the problem here, even that curl is throwing timeouts
When failing test is executing 2400 iterations it's passing, it seems that at my laptop, the limit is 2403, 2404 starts breaking.
Nix seems to not be the problem, php installed through brew is acting the same.
I was able to reproduce this issue at macbooks with Intel and M1 processors.