-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
[Process] Process Manager #23596
[Process] Process Manager #23596
Conversation
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.
While this solution as is, might not be suitable for enterprise companies, it's a very nice addition to the process component imo.
I'd like to see some architectural changes to this class as I mentioned in my comments, but implementation wise, it looks similar to something I've written and used before.
* | ||
* @author John Nickell <[email protected]> | ||
*/ | ||
class ProcessManager |
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.
I would like to see a different name here, what about something towards ParallelProcessRunner
or ProcessRunnerQueue
? Naming Classes - How to avoid calling everything a "Manager"?
Also from an architectural point of view, I'd like to see an interface implemented here and the constants either in that interface or a dedicated final (with private constructor) class. This will avoid difference references and gives a proper decoration possibility.
protected function init() | ||
{ | ||
if ($this->maxConcurrent === 0 || count($this->procs) < $this->maxConcurrent) { | ||
$next = $this->queue->dequeue(); |
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.
Could make a guard clause here, prevents nesting while not needed
/** @var Process $process */ | ||
$process = $next[0]; | ||
/** @var callable|null $callback */ | ||
$callback = $next[1]; |
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.
Could use list($process, $callback) = $this->queue->dequeue();
instead. Don't think typehints are needed here as it's all internal anyway.
usleep($this->usleepDelay); | ||
foreach ($this->procs as $pid => $process) { | ||
$process->checkTimeout(); | ||
if (!$process->isRunning()) { |
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.
Could be turned into a guard clause as well by using continue;
/** | ||
* Starts a process if possible. | ||
*/ | ||
protected function init() |
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.
Should either be private or public
* | ||
* @throws ProcessFailedException When a process fails | ||
*/ | ||
protected function tick($errorBehavior) |
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.
Should either be private or public
/** | ||
* Stop running processes. | ||
*/ | ||
protected function stop() |
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.
Should either be private or public
|
||
namespace Symfony\Component\Process; | ||
|
||
use SplQueue; |
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.
I believe this should always be an \SplQueue
usage and global namespaces are never important in Symfony (correct me if I'm wrong here)
* @param callable|null $callback A PHP callback to run whenever there is some | ||
* output available on STDOUT or STDERR | ||
*/ | ||
public function add(Process $process, callable $callback = null) |
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.
what about error behavior per process? add($proces, $callback, $errorBehavior)
*/ | ||
public function clear() | ||
{ | ||
$this->queue = new SplQueue(); |
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.
new \SplQueue()
indeed
* | ||
* @var int | ||
*/ | ||
protected $maxConcurrent; |
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.
private; doblock seems redundant. Same for other constructor args.
Thank you @johnnickell. But more importantly, I think this approach is not good enough for ending up in Symfony. The core issue is that the Process component hides a The proper design would need a single So, my stand here is that we should refactor the Process class to inject it a small event loop (eg as an optional constructor argument so that we keep BC). Then, once that refacto is done, a process manager will be trivial to write - correctly. :) Thank you again for your PR, sorry for the negative (but hopefully constructive) comment :) |
@nicolas-grekas Thank you very much for taking the time to look at this and provide feedback. I don't have experience using an event loop with PHP, so the refactor might be beyond my current skill. I would be glad to add the requested changes as an exercise, even though this pull request will be closed. I'll continue to dig into the process class and experiment. If I come up with something useful, I will definitely share it. Thank you again! |
@johnnickell, that event loop idea is not a trivial one, I may give it a try in the next weeks... Meanwhile, I think we can close this PR. As you want of course. |
What state is this in? I'd love this feature build in Symfony. Gotta hack it around the whole process now :( |
Simple configurable process manager. Processes are added to the manager, then they can be run in parallel.
Example Usage
By default the process manager will throw an exception if any of the child processes fail. If you would like to get around this, you can specify that when calling the run method: