Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
9 / 9
CRAP
100.00% covered (success)
100.00%
50 / 50
Factory
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
9 / 9
17
100.00% covered (success)
100.00%
50 / 50
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
5 / 5
 addEnvs
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 throwExceptionsOnFailure
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 addProcess
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 run
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 start
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 startDetached
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 getProcessInfos
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
5 / 5
 launch
100.00% covered (success)
100.00%
1 / 1
8
100.00% covered (success)
100.00%
21 / 21
1<?php
2
3namespace Qmp\Laravel\AsyncProcessFactory;
4
5use Illuminate\Support\Collection;
6use Illuminate\Support\Facades\Log;
7use Qmp\Laravel\AsyncProcessFactory\Exceptions\SubProcessException;
8
9class Factory
10{
11    /**
12     * The process stack collection
13     *
14     * @var Illuminate\Support\Collection
15     */
16    protected $processStack;
17
18    /**
19     * The artisan command for all the processes in the factory
20     *
21     * @param string $command
22     */
23    protected $command;
24
25    /**
26     * The default callback
27     *
28     * @var callable
29     */
30    protected $callBack = null;
31
32    /**
33     * Run or start
34     *
35     * @var string
36     */
37    protected $launchType = null;
38
39    /**
40     * The process stack infos
41     *
42     * @var Illuminate\Support\Collection
43     */
44    protected $processInfos;
45
46    /**
47     * Envs vars
48     *
49     * @var Collection
50     */
51    protected $envs;
52
53    /**
54     * If process fail, throw exception
55     *
56     * @var boolean
57     */
58    protected $throw = false;
59
60    /**
61     * Create a new process factory
62     *
63     * @param string $command
64     */
65    public function __construct(string $command)
66    {
67        $this->processStack = collect([]);
68        $this->processInfos = collect([]);
69        $this->command = $command;
70        $this->envs = collect([]);
71    }
72
73    /**
74     * Undocumented function
75     *
76     * @param array $envs
77     * @return void
78     */
79    public function addEnvs(array $envs)
80    {
81        $this->envs = $this->envs->merge($envs);
82    }
83
84    /**
85     * Undocumented function
86     *
87     * @param boolean $trhow
88     * @return void
89     */
90    public function throwExceptionsOnFailure($throw = true)
91    {
92        $this->throw = $throw;
93    }
94
95    /**
96     * Add a process to the stack
97     *
98     * @param array $options
99     * @return void
100     */
101    public function addProcess(array $options = []): void
102    {
103        $process = new ProcessHandler($this->command);
104        $process->addOptions($options);
105
106        $this->processStack->put($process->getkey(), $process);
107    }
108
109    /**
110     * Start processes one by one
111     *
112     * @param callable $callback
113     * @return void
114     */
115    public function run(callable $callback = null): void
116    {
117        $this->callBack = $callback;
118        $this->launchType = 'run';
119        $this->launch();
120    }
121
122    /**
123     * Start Processes in parralel
124     *
125     * @param callable $callback
126     * @return void
127     */
128    public function start(callable $callback = null): void
129    {
130        $this->callBack = $callback;
131        $this->launchType = 'start';
132        $this->launch();
133    }
134
135    /**
136     * Start Processes in parralel and detached
137     *
138     * @param callable $callback
139     * @return void
140     */
141    public function startDetached(): void
142    {
143        $this->launchType = 'startDetached';
144        $this->launch();
145    }
146
147    /**
148     * Start Processes in parralel
149     *
150     * @param callable $callback
151     * @return Illuminate\Support\Collection
152     */
153    public function getProcessInfos(callable $closure = null): Collection
154    {
155        if ($closure) {
156            return $this->processInfos->mapWithKeys(function ($process) use ($closure) {
157                return [$closure($process->get('options')) => $process];
158            });
159        }
160
161        return $this->processInfos;
162    }
163
164    /**
165     * Launch process stack
166     *
167     * @return void
168     */
169    protected function launch(): void
170    {
171        try {
172            $message = $this->launchType === 'startDetached' ? 'start detached from' : $this->launchType . ' in';
173
174            $this->processStack->each(function ($process, $key) use ($message) {
175                Log::debug("Process $message factory ! {task #$key}");
176                if (!$process->isRunning()) {
177                    $started = $process->setEnv($this->envs)->{$this->launchType}($this->callBack);
178                    $this->processInfos->push($process->getInfos($started));
179                }
180            });
181
182            if ($this->launchType !== 'startDetached') {
183                while ($this->processStack->count()) {
184                    $this->processStack->each(function ($process, $key) {
185                        if (!$process->isRunning()) {
186                            $this->processStack->forget($key);
187                            Log::debug("Process in factory is done ! {task #$key}");
188                        }
189                    });
190                }
191            }
192        } catch (SubProcessException $e) {
193            if ($this->throw) {
194                throw $e;
195            } else {
196                Log::debug("Process in factory fail ! {task #" . $e->getKey() . "}");
197                $this->processStack->forget($e->getKey());
198                $this->launch();
199            }
200        }
201    }
202}