Completed
Pull Request — master (#21)
by Akihito
04:50
created

Snidel::__destruct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 3
eloc 7
nc 3
nop 0
1
<?php
2
declare(ticks = 1);
3
4
namespace Ackintosh;
5
6
use Ackintosh\Snidel\Config;
7
use Ackintosh\Snidel\Fork\Container;
8
use Ackintosh\Snidel\Log;
9
use Ackintosh\Snidel\Pcntl;
10
use Ackintosh\Snidel\Task\Task;
11
12
class Snidel
13
{
14
    /** @var \Ackintosh\Snidel\Config */
15
    private $config;
16
17
    /** @var \Ackintosh\Snidel\Fork\Container */
18
    private $container;
19
20
    /** @var \Ackintosh\Snidel\Pcntl */
21
    private $pcntl;
22
23
    /** @var \Ackintosh\Snidel\Log */
24
    private $log;
25
26
    /** @var array */
27
    private $signals = [
28
        SIGTERM,
29
        SIGINT,
30
    ];
31
32
    /**
33
     * @param   array $parameter
34
     * @throws \RuntimeException
35
     */
36
    public function __construct($parameter = [])
37
    {
38
        $this->config = new Config($parameter);
39
        $this->log = new Log($this->config->get('ownerPid'), $this->config->get('logger'));
40
        $this->container = new Container($this->config, $this->log);
41
        $this->container->forkMaster();
42
        $this->pcntl = new Pcntl();
43
44
        foreach ($this->signals as $sig) {
45
            $this->pcntl->signal(
46
                $sig,
47
                function ($sig)  {
48
                    $this->log->info('received signal. signo: ' . $sig);
49
                    $this->log->info('--> sending a signal " to children.');
50
                    $this->container->sendSignalToMaster($sig);
51
                    $this->log->info('<-- signal handling has been completed successfully.');
52
                    exit;
53
                },
54
                false
55
            );
56
        }
57
58
        $this->log->info('parent pid: ' . $this->config->get('ownerPid'));
59
    }
60
61
    /**
62
     * this method uses master / worker model.
63
     *
64
     * @param   callable    $callable
65
     * @param   mixed       $args
66
     * @param   string      $tag
67
     * @return  void
68
     * @throws  \RuntimeException
69
     */
70
    public function process($callable, $args = [], $tag = null)
71
    {
72
        try {
73
            $this->container->enqueue(new Task($callable, $args, $tag));
74
        } catch (\RuntimeException $e) {
75
            $this->log->error('failed to enqueue the task: ' . $e->getMessage());
76
            throw $e;
77
        }
78
79
        $this->log->info('queued task #' . $this->container->queuedCount());
80
    }
81
82
    /**
83
     * waits until all tasks that queued by Snidel::fork() are completed
84
     *
85
     * @return  void
86
     */
87
    public function wait()
88
    {
89
        $this->container->wait();
90
    }
91
92
    /**
93
     * returns generator which returns a result
94
     *
95
     * @return \Generator
96
     */
97
    public function results()
98
    {
99
        foreach($this->container->results() as $r) {
100
            yield $r;
101
        }
102
    }
103
104
    /**
105
     * @return  bool
106
     */
107
    public function hasError()
108
    {
109
        return $this->container->hasError();
110
    }
111
112
    /**
113
     * @return  \Ackintosh\Snidel\Error
114
     */
115
    public function getError()
116
    {
117
        return $this->container->getError();
118
    }
119
120
    public function __destruct()
121
    {
122
        if ($this->config->get('ownerPid') === getmypid()) {
123
            $this->wait();
124
            if ($this->container->existsMaster()) {
125
                $this->log->info('shutdown master process.');
126
                $this->container->sendSignalToMaster();
127
            }
128
129
            unset($this->container);
130
        }
131
    }
132
}
133