-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit cd215d7
Showing
20 changed files
with
1,347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/.gitattributes export-ignore | ||
/.gitignore export-ignore | ||
/.github export-ignore | ||
/tests export-ignore | ||
/phpunit.xml export-ignore | ||
/.php-cs-fixer.dist.php export-ignore |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
composer.lock | ||
vendor/ | ||
var/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
|
||
$finder = PhpCsFixer\Finder::create() | ||
->in(__DIR__ . '/src') | ||
->in(__DIR__ . '/tests') | ||
; | ||
|
||
$rules = [ | ||
// Rules that follow PSR-12 standard. | ||
'@PER-CS2.0' => true, | ||
|
||
// Rules that follow PSR-12 standard. This set contains rules that are risky. | ||
'@PER-CS2.0:risky' => true, | ||
|
||
// PHP arrays should be declared using the short syntax. | ||
'array_syntax' => ['syntax' => 'short'], | ||
|
||
// Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one. | ||
'align_multiline_comment' => true, | ||
|
||
// A single space or none should be between cast and variable. | ||
'cast_spaces' => true, | ||
|
||
// There should not be any empty comments. | ||
'no_empty_comment' => true, | ||
|
||
// Unused use statements must be removed. | ||
'no_unused_imports' => true, | ||
|
||
// Scalar types should always be written in the same form. int not integer, bool not boolean, float not real or double. | ||
'phpdoc_scalar' => true, | ||
|
||
// Single line @var PHPDoc should have proper spacing. | ||
'phpdoc_single_line_var_spacing' => true, | ||
|
||
// Removes extra blank lines after summary and after description in PHPDoc. | ||
'phpdoc_trim' => true, | ||
|
||
// @var and @type annotations must have type and name in the correct order. | ||
'phpdoc_var_annotation_correct_order' => true, | ||
|
||
// Remove useless (semicolon) statements. | ||
'no_empty_statement' => true, | ||
|
||
// There MUST NOT be spaces around offset braces. | ||
'no_spaces_around_offset' => true, | ||
|
||
// Force strict types declaration in all files. | ||
'declare_strict_types' => true, | ||
|
||
// Comparisons should be strict. | ||
'strict_comparison' => true, | ||
|
||
// Ordering use statements | ||
'ordered_imports' => true, | ||
|
||
// Replace get_class calls on object variables with class keyword syntax. | ||
'get_class_to_class_keyword' => true, | ||
|
||
// Removes @param, @return and @var tags that don’t provide any useful information. | ||
'no_superfluous_phpdoc_tags' => true, | ||
|
||
// Multi-line arrays, arguments list, parameters list and match expressions must have a trailing comma. | ||
'trailing_comma_in_multiline' => [ | ||
'after_heredoc' => true, | ||
'elements' => ['arrays', 'match', 'arguments', 'parameters'], | ||
], | ||
|
||
// Empty body of class, interface, trait, enum or function must be abbreviated as {} and placed on the same line | ||
'single_line_empty_body' => false, | ||
]; | ||
|
||
return (new PhpCsFixer\Config()) | ||
->setCacheFile(__DIR__ . '/var/.php-cs-fixer.cache') | ||
->setFinder($finder) | ||
->setRules($rules) | ||
->setRiskyAllowed(true) | ||
; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
Copyright (c) 2024 [email protected] | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
# PhpRunner runtime for symfony applications | ||
![PHP >=8.2](https://img.shields.io/badge/PHP->=8.2-777bb3.svg?style=flat) | ||
![Symfony ^6.4|^7.0](https://img.shields.io/badge/Symfony-^7.0-374151.svg?style=flat) | ||
[![Version](https://img.shields.io/github/v/tag/luzrain/phprunner-bundle?label=Version&filter=v*.*.*&sort=semver&color=374151)](../../releases) | ||
[![Tests Status](https://img.shields.io/github/actions/workflow/status/luzrain/phprunner-bundle/tests.yaml?label=Tests&branch=master)](../../actions/workflows/tests.yaml) | ||
|
||
This bundle provides a [PhpRunner](https://github.com/luzrain/phprunner) integration with Symfony framework to run your application in a highly efficient event-loop based runtime. | ||
|
||
> [!NOTE] | ||
> This tool is in development now | ||
## Getting started | ||
### Install composer packages | ||
```bash | ||
$ composer require luzrain/phprunner-bundle | ||
``` | ||
|
||
### Enable the bundle | ||
```php | ||
<?php | ||
// config/bundles.php | ||
|
||
return [ | ||
// ... | ||
Luzrain\PhpRunnerBundle\PhpRunnerBundle::class => ['all' => true], | ||
]; | ||
``` | ||
|
||
### Configure the bundle | ||
A minimal configuration might look like this. | ||
For all available options with documentation, see the command output. | ||
```bash | ||
$ bin/console config:dump-reference phprunner | ||
``` | ||
|
||
```yaml | ||
# config/packages/phprunner.yaml | ||
|
||
phprunner: | ||
servers: | ||
- name: 'Symfony webserver' | ||
listen: http://0.0.0.0:80 | ||
processes: 4 | ||
|
||
reload_strategy: | ||
exception: | ||
active: true | ||
|
||
file_monitor: | ||
active: true | ||
``` | ||
### Start application | ||
```bash | ||
$ APP_RUNTIME=Luzrain\\PhpRunnerBundle\\Runtime php public/index.php start | ||
``` | ||
|
||
\* For better performance, install the _php-uv_ extension. | ||
|
||
## Reload strategies | ||
Because of the asynchronous nature of the server, the workers reuse loaded resources on each request. This means that in some cases we need to restart workers. | ||
For example, after an exception is thrown, to prevent services from being in an unrecoverable state. Or every time you change the code in the IDE. | ||
There are a few restart strategies that are implemented and can be enabled or disabled depending on the environment. | ||
|
||
- **exception** | ||
Reload worker each time that an exception is thrown during the request handling. | ||
- **max_requests** | ||
Reload worker on every N request to prevent memory leaks. | ||
- **file_monitor** | ||
Reload all workers each time you change the files**. | ||
- **always** | ||
Reload worker after each request. | ||
|
||
** It is highly recommended to install the _php-inotify_ extension for file monitoring. Without it, monitoring will work in polling mode, which can be very cpu and disk intensive for large projects. | ||
|
||
See all available options for each strategy in the command output. | ||
```bash | ||
$ bin/console config:dump-reference phprunner reload_strategy | ||
``` | ||
|
||
## Scheduler | ||
Periodic tasks can be configured with attributes or with tags in configuration files. | ||
Schedule string can be formatted in several ways: | ||
- An integer to define the frequency as a number of seconds. Example: _60_ | ||
- An ISO8601 datetime format. Example: _2023-08-01T01:00:00+08:00_ | ||
- An ISO8601 duration format. Example: _PT1M_ | ||
- A relative date format as supported by DateInterval. Example: _1 minutes_ | ||
- A cron expression**. Example: _*/1 * * * *_ | ||
|
||
** Note that you need to install the [dragonmantank/cron-expression](https://github.com/dragonmantank/cron-expression) package if you want to use cron expressions as schedule strings | ||
|
||
```php | ||
<?php | ||
|
||
use Luzrain\PhpRunnerBundle\Attribute\AsTask; | ||
|
||
/** | ||
* Attribute parameters | ||
* name: Task name | ||
* schedule: Task schedule in any format | ||
* method: method to call, __invoke by default | ||
* jitter: Maximum jitter in seconds that adds a random time offset to the schedule. Use to prevent multiple tasks from running at the same time | ||
*/ | ||
#[AsTask(name: 'My scheduled task', schedule: '1 minutes')] | ||
final class TaskService | ||
{ | ||
public function __invoke() | ||
{ | ||
// ... | ||
} | ||
} | ||
``` | ||
|
||
## Supervisor | ||
Supervisor can be configured with attributes or with tags in configuration files. | ||
Processes are kept alive and wake up if one of them dies. | ||
|
||
```php | ||
<?php | ||
|
||
use Luzrain\PhpRunnerBundle\Attribute\AsProcess; | ||
|
||
/** | ||
* Attribute parameters | ||
* name: Process name | ||
* processes: number of processes | ||
* method: method to call, __invoke by default | ||
*/ | ||
#[AsProcess(name: 'My worker', processes: 1)] | ||
final class ProcessService | ||
{ | ||
public function __invoke() | ||
{ | ||
// ... | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
{ | ||
"name": "luzrain/phprunner-bundle", | ||
"description": "Phprunner runtime for symfony applications", | ||
"keywords": ["phprunner", "symfony", "runtime", "php-runtime"], | ||
"homepage": "https://github.com/luzrain/phprunner-bundle", | ||
"type": "symfony-bundle", | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "Anton Zenkov", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"require": { | ||
"php": "^8.2", | ||
"ext-pcntl": "*", | ||
"ext-posix": "*", | ||
"luzrain/phprunner": "dev-master", | ||
"psr/http-factory": "^1.0", | ||
"symfony/config": "^7.0", | ||
"symfony/dependency-injection": "^7.0", | ||
"symfony/error-handler": "^7.0", | ||
"symfony/http-kernel": "^7.0", | ||
"symfony/psr-http-message-bridge": "^7.0", | ||
"symfony/runtime": "^7.0" | ||
}, | ||
"require-dev": { | ||
"friendsofphp/php-cs-fixer": "^3.48", | ||
"guzzlehttp/guzzle": "^7.8", | ||
"phpunit/phpunit": "^10.5", | ||
"symfony/framework-bundle": "^7.0" | ||
}, | ||
"suggest": { | ||
"ext-uv": "For better performance", | ||
"ext-inotify": "For effective file monitoring", | ||
"dragonmantank/cron-expression": "For parse cron expressions" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"Luzrain\\PhpRunnerBundle\\": "src/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"Luzrain\\PhpRunnerBundle\\Test\\": "tests/" | ||
} | ||
}, | ||
"config": { | ||
"sort-packages": true, | ||
"allow-plugins": { | ||
"symfony/runtime": true | ||
} | ||
} | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Luzrain\PhpRunnerBundle; | ||
|
||
use Symfony\Component\Config\ConfigCache; | ||
use Symfony\Component\Config\Resource\FileResource; | ||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; | ||
|
||
final class ConfigLoader implements CacheWarmerInterface | ||
{ | ||
private array $config; | ||
private ConfigCache $cache; | ||
private string $yamlConfigFilePath; | ||
|
||
public function __construct(string $projectDir, string $cacheDir, bool $isDebug) | ||
{ | ||
$this->yamlConfigFilePath = \sprintf('%s/config/packages/phprunner.yaml', $projectDir); | ||
$cacheConfigFilePath = \sprintf('%s/phprunner_config.cache.php', $cacheDir); | ||
$this->cache = new ConfigCache($cacheConfigFilePath, $isDebug); | ||
} | ||
|
||
public function isOptional(): bool | ||
{ | ||
return false; | ||
} | ||
|
||
public function warmUp(string $cacheDir, string $buildDir = null): array | ||
{ | ||
$resources = \is_file($this->yamlConfigFilePath) ? [new FileResource($this->yamlConfigFilePath)] : []; | ||
$this->cache->write(\sprintf('<?php return %s;', \var_export($this->config, true)), $resources); | ||
|
||
return []; | ||
} | ||
|
||
public function warmUpInFork(KernelFactory $kernelFactory): void | ||
{ | ||
if (\pcntl_fork() === 0) { | ||
$kernelFactory->createKernel()->boot(); | ||
exit; | ||
} else { | ||
pcntl_wait($status); | ||
unset($status); | ||
} | ||
} | ||
|
||
public function isFresh(): bool | ||
{ | ||
return $this->cache->isFresh(); | ||
} | ||
|
||
private function getConfigCache(): array | ||
{ | ||
return $this->config ??= require $this->cache->getPath(); | ||
} | ||
|
||
public function setConfig(array $config): void | ||
{ | ||
$this->config[0] = $config; | ||
} | ||
|
||
public function setProcessConfig(array $config): void | ||
{ | ||
$this->config[1] = $config; | ||
} | ||
|
||
public function setSchedulerConfig(array $config): void | ||
{ | ||
$this->config[2] = $config; | ||
} | ||
|
||
public function getConfig(): array | ||
{ | ||
return $this->getConfigCache()[0]; | ||
} | ||
|
||
public function getProcessConfig(): array | ||
{ | ||
return $this->getConfigCache()[1]; | ||
} | ||
|
||
public function getSchedulerConfig(): array | ||
{ | ||
return $this->getConfigCache()[2]; | ||
} | ||
} |
Oops, something went wrong.