Skip to content

Commit

Permalink
feat(opcache): added generation of opcache.blacklist_file when using …
Browse files Browse the repository at this point in the history
…coroutines, because of segfaults when using swoole with opcache
  • Loading branch information
Rastusik committed Feb 6, 2023
1 parent 066d5aa commit 0cade70
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 2 deletions.
13 changes: 12 additions & 1 deletion docs/configuration-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,15 @@ final class EntityManagerStabilityChecker implements StabilityChecker

When the checker returns false, the coroutine engine will forget the unstable service and will fetch a fresh instance
from the DI container. Otherwise the engine will mark the service instance as unused and will assign it to a coroutine
in the next web request.
in the next web request.

## Opcache problems

This bundle overrides generated Symfony container class, it renames the original container class (and corresponding filename)
and generates a new container class which extends the original class.

Including these two relatively big classes into the engine at runtime somehow corrupts the Opcache
(in cases where `opcache.enable_cli` is enabled, which can save some RAM, not sure why) and results in segmentation fault.
That is why this bundle generates a blacklist file which can be used for the `opcache.blacklist_filename` setting.
With this blacklist file, Opcache can still be enabled for CLI and there are no segmentation faults.
The generated file is stored under this path: `{$PROJECT_DIR}/var/cache/{$ENV}/swoole_bundle/opcache/blacklist.txt`
9 changes: 9 additions & 0 deletions src/Bridge/Symfony/Container/ContainerModifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace K911\Swoole\Bridge\Symfony\Container;

use K911\Swoole\Bridge\Symfony\Bundle\DependencyInjection\ContainerConstants;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\Filesystem\Filesystem;
Expand Down Expand Up @@ -196,6 +197,14 @@ private static function overrideGeneratedContainer(ReflectionClass $reflContaine

$containerSource = file_get_contents($containerFile);
$overriddenSource = str_replace('class '.$containerClass, 'class '.$overriddenClass, $containerSource);

// dump opcache.blacklist_filename
$blacklistFile = $cacheDir.DIRECTORY_SEPARATOR.ContainerConstants::PARAM_CACHE_FOLDER.DIRECTORY_SEPARATOR.'opcache'.DIRECTORY_SEPARATOR.'blacklist.txt';
$blacklistFiles = [$containerFile, $overriddenFile];
$blacklistFileContent = implode(PHP_EOL, $blacklistFiles).PHP_EOL;
$fs->dumpFile($blacklistFile, $blacklistFileContent);

// methods override
$ignoredMethods = self::getIgnoredGetters();
$methods = $reflContainer->getMethods(\ReflectionMethod::IS_PROTECTED);
$methodsCodes = [];
Expand Down
36 changes: 36 additions & 0 deletions tests/Feature/SwooleServerCoroutinesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

use Doctrine\ORM\EntityManager;
use K911\Swoole\Client\HttpClient;
use K911\Swoole\Tests\Fixtures\Symfony\TestAppKernel;
use K911\Swoole\Tests\Fixtures\Symfony\TestBundle\Entity\Test;
use K911\Swoole\Tests\Fixtures\Symfony\TestBundle\Service\NoAutowiring\ResetCountingRegistry;
use K911\Swoole\Tests\Fixtures\Symfony\TestBundle\Test\ServerTestCase;
use Swoole\Coroutine\WaitGroup;
use Symfony\Bundle\FrameworkBundle\Console\Application;

final class SwooleServerCoroutinesTest extends ServerTestCase
{
Expand All @@ -19,6 +21,30 @@ protected function setUp(): void
$this->deleteVarDirectory();
}

/**
* @dataProvider kernelEnvironmentDataProvider
*/
public function testOpcacheBlacklistFileGeneration(array $options): void
{
/** @var TestAppKernel $kernel */
$kernel = static::createKernel($options);
$application = new Application($kernel);
$application->find('cache:clear'); // this will trigger cache generation
$blacklistFile = $kernel->getCacheDir().DIRECTORY_SEPARATOR.'swoole_bundle'.DIRECTORY_SEPARATOR.'opcache'.DIRECTORY_SEPARATOR.'blacklist.txt';

self::assertFileExists($blacklistFile);

$content = file_get_contents($blacklistFile);

self::assertIsString($content);

$files = explode(PHP_EOL, trim($content));

foreach ($files as $file) {
self::assertFileExists($file);
}
}

/**
* @dataProvider coroutineTestDataProvider
*/
Expand Down Expand Up @@ -520,6 +546,16 @@ public function coroutineTestDataProviderForTaskWorkers(): array
];
}

public function kernelEnvironmentDataProvider(): array
{
return [
[['environment' => 'prod', 'debug' => false, 'override_prod_env' => 'coroutines']],
[['environment' => 'prod', 'debug' => true, 'override_prod_env' => 'coroutines']],
[['environment' => 'coroutines', 'debug' => false]],
[['environment' => 'coroutines', 'debug' => true]],
];
}

private function generateNotExistingCustomTestFile(): string
{
return '/tmp/tfile-coroutines-'
Expand Down
25 changes: 24 additions & 1 deletion tests/Fixtures/Symfony/TestBundle/Test/ServerTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,32 @@ public function assertProcessFailed(Process $process): void

protected static function createKernel(array $options = []): KernelInterface
{
if (null === static::$class) {
static::$class = static::getKernelClass();
}

$options['environment'] = self::resolveEnvironment($options['environment'] ?? null);
$env = $options['environment'];

if (isset($options['debug'])) {
$debug = $options['debug'];
} elseif (isset($_ENV['APP_DEBUG'])) {
$debug = $_ENV['APP_DEBUG'];
} elseif (isset($_SERVER['APP_DEBUG'])) {
$debug = $_SERVER['APP_DEBUG'];
} else {
$debug = true;
}

$overrideProdEnv = null;

if (isset($options['override_prod_env'])) {
$overrideProdEnv = $options['override_prod_env'];
} elseif (isset($_SERVER['OVERRIDE_PROD_ENV'])) {
$overrideProdEnv = $_SERVER['OVERRIDE_PROD_ENV'];
}

return parent::createKernel($options);
return new static::$class($env, $debug, $overrideProdEnv);
}

protected static function getKernelClass(): string
Expand Down

0 comments on commit 0cade70

Please sign in to comment.