-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Process] Add a Process Manager #8753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* | ||
* @return Process The new process | ||
* | ||
* @throws \RuntimeException When process can't be launch or is stopped |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The phpdocs in this interface mix up \RuntimeException
and RuntimeException
Is there any way to add processes to queue on the fly? for example I have 10000 users in DB. and for each user I want to call some process (but only 5 in parallel). So it's silly to get all 10000 users and create 10000 processes at once. Maybe add some process providers, or add events |
Cool feature 👍 |
|
||
namespace Symfony\Component\Process\Exception; | ||
|
||
use Symfony\Component\Process\Process; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused
What about a process manager builder ? Something like this : namespace Symfony\Component\Process\Manager;
class ManagerBuilder
{
public function chain(array $processes)
{
$manager = new ProcessManager();
$manager->setMaxParallelProcesses(1);
foreach ($processes as $name => $process) {
$manager->add($process, $name);
}
return $manager;
}
public function parallel(array $processes)
{
$manager = new ProcessManager();
foreach ($processes as $name => $process) {
$manager->add($process, $name);
}
return $manager;
}
} usage example : $manager = $builder->chain(
$builder->parallel(
$builder->chain(array($process1, $process2, $process3)),
$builder->chain(array($process4, $process5))
),
$process6
);
$manager->run(); any ideas ? |
@romainneutron Maybe also smth like auto method from node.js async library?
|
Hello, node.js is an event driven environment, and async.js is a tool to deal with async behaviors. Actually, Process is not asynchronous. The So this kind of behavior could not be ported. Anyway, not in the same fashion. If you're interested in async process, have a look at react project, particularly the child process PR and the https://github.com/reactphp/promise project that provides promise for the react environment. This is out of topic because this environment requires non-blocking calls, what's not at all the case of Symfony. |
@romainneutron I mean ability to call processes in some order. But looks like I can achieve this using chain and parallel methods: for example $builder->chain(
$builder->parallel($getDataProcess, $makeFolderProcess)),
$writeFileProcess,
$emailLinkProcess
); |
Yes it works. The difference is the ability to pass the output between process. This is something that we could implement in the future, see FR #8161 |
I mean that |
@fabpot what's the state on this one ? Could it be merge in 2.4 ? If so, I've to finish the ManagerBuilder and work on the doc ASAP. If it's too late for this, can we merge the interfaces (2 first commits) so the ProcessManager can be used and tested without using a custom symfony repo ? |
We are not in a hurry. 2.4 end of dev is at the end of September. I haven't had time to have a look at this PR yet, but I will soon. |
👍 Great feature! Would love to see this integrated into 2.4. |
I'd really like to see something like a ProcessProvider: <?php
class ManagerBuilder
{
public function chain(ProcessProviderInterface $processProvider)
{
$manager = ProcessManager::create();
$manager->setMaxParallelProcesses(1);
foreach ($processProvider as $name => $process) {
$manager->add($process, $name);
}
return $manager;
}
public function parallel(ProcessProviderInterface $processProvider)
{
$manager = ProcessManager::create();
foreach ($processProvider as $name => $process) {
$manager->add($process, $name);
}
return $manager;
}
} Usage example: <?php
// Implemets ProcessProviderInterface
$batchProcessProvider = new BatchProcessProvider();
$batchProcessProvider
->setCommandTemplate(
'exec php -f app/console project:update-users --limit=%limit% --offset=%offset%'
)
->setPlaceholders(array(
'%limit%' => 'limit',
'%offset%' => 'offset'
))
->setTotalCount(1000000)
->setLimit(20000)
;
$q = $em->createQuery('select u from MyProject\Model\User u');
$doctrineBatchProcessProvider = BatchProcessProvider::createFromIterator(
$q->iterate(),
'exec php -f app/console project:update-user-attributes --id=%id%',
array('%id%' => 'id')
);
$manager = $builder->chain(
$builder->parallel(
$builder->chain($batchProcessProvider),
$builder->chain(ProcessProvider::createFromArray(
array(
$process4,
'processName' => $process5
)
)),
$doctrineBatchProcessProvider
),
ProcessProvider::createFromArray(array($process6))
);
$manager->run(); /cc @sirian |
@tPl0ch imho - it's silly to add all processes at start point like in ManagerBuilder::parallel example (to decrease memory usage). |
ProcessProvider is indeed something that would be quite nice. But we need to separate concerns and ProcessProvider should not deal directly with ProcessManager that has the job to run multiple instancied processes. I think it should be implemented at higher level than ProcessManager. To do so, we need to some informations about its state like |
ping @fabpot |
@fabpot If this PR is not mergeable in 2.4, can we at least think about merging the interfaces (two first commits) ? |
I will need more time on this one as I have something equivalent (but not exactly). That's something we will be able to do in 2.5. |
Okay then, bring the code at symfonycon hackday ;) |
…mainneutron) This PR was merged into the 2.2 branch. Discussion ---------- [Process][2.2] Fix 9182 : random failure on pipes tests | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #9182 | License | MIT I'm not a big fan of this fix, but - at least - it works. With this code, finally, Process does not behave the same at all on Windows and Linux. This patch does not smells very good but it solves the random failing test issue (that produced at runtime too). Actually, calling `proc_get_status` within the waiting loop introduced the bug. So this PR reverts to the previous behavior (consider a process running as long as pipes give data). On Windows, this is not the same behavior as we're not using streams but file handles. Whereas the feof of a stream is detected when the other side closes, the feof of a file handle can be reached at any time. So, on Windows, `proc_get_status` is called (checking the feof of the file handle might be positive until the executable outputs something), and we consider a process running as long as the information returned says it's running. We could think of decouple windows and linux logic in two separated objects, using the interfaces I introduced in #8753. This could bring much more readability and make the code more easy to understand. Commits ------- 64a0b40 [Process] Fix #9182 : random failure on pipes tests
*/ | ||
private function addFailureToProcess($process, $e, $strategy) | ||
{ | ||
$process->addFailure($e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can cause a memory leak if the process is being retried using STRATEGY_RETRY.
The "failures" array will get bigger and bigger with each process retry.
Example below:
$manager = new ProcessManager();
$manager->setTimeoutStrategy(ProcessManager::STRATEGY_RETRY);
for ($i = 0; $i < 10; $i++) {
$p = new Process("while true; do date > /dev/null; done;");
$p->setTimeout(1);
$manager->add($p);
}
$manager->start();
while ($manager->isRunning()) {
echo sprintf("Memory usage: %dKB/ %dKB\n", round(memory_get_usage(true) / 1024), memory_get_peak_usage(true) / 1024);
}
ping @fabpot @romainneutron |
Hello,
I'm looking for feedback for this process manager implementation.
This PR adds a ProcessableInterface that is implements by both
Process
andProcessManager
.Once the API is ok, the remaining tasks are :
Usage examples
Run 4 jobs in parallel
Run 4 jobs in queue
Run 2 queues of 2 jobs in parallel