Start the daemon with workers (by fork()ing)

@return TaskDaemon
546454
public function start()
    {
        if (count($this->tasks) == 0)
            throw new \Exception("There are no tasks defined - can not start");

        $this->started = true;

        $options = static::getOptions();
        $debug = @$options['debug'] === true;

        $pidFile = $options['pid_file'];
        if (!$pidFile)
            throw new \Exception("No pid_file in the config");

        $fpPid = fopen($pidFile, "c");
        if (!$fpPid)
            throw new \Exception("Could not open " . $pidFile);

        if (!flock($fpPid, LOCK_EX | LOCK_NB)) {
            fclose($fpPid);
            if ($debug)
                echo "==> Daemon already running" . PHP_EOL;
            return $this;
        }

        if ($debug)
            echo "==> Starting the daemon... " . PHP_EOL;

        $fork = pcntl_fork();
        if ($fork < 0)
            throw new \Exception("fork() failed: $fork");
        else if ($fork)
            return $this;

        ftruncate($fpPid, 0);
        fwrite($fpPid, getmypid() . PHP_EOL);
        fflush($fpPid);
        chmod($pidFile, 0666);

        declare(ticks = 1);

        $exitCallback = function ($signo) use ($fpPid, $pidFile, $debug) {
            if ($debug)
                echo "==> Cleaning and exiting" . PHP_EOL;

            foreach ($this->pids as $pid) {
                if ($debug)
                    echo "==> Terminating worker PID $pid" . PHP_EOL;
                posix_kill($pid, SIGTERM);
            }
            foreach ($this->pids as $pid)
                pcntl_waitpid($pid, $status);

            flock($fpPid, LOCK_UN);
            fclose($fpPid);
            @unlink($pidFile);

            if ($debug)
                echo "==> Daemon is shut down" . PHP_EOL;
            exit;
        };

        pcntl_signal(SIGTERM, $exitCallback);
        pcntl_signal(SIGINT, $exitCallback);
        pcntl_signal_dispatch();

        $sid = posix_setsid();
        if ($sid < 0)
            throw new \Exception("setsid() failed: $sid");

        $gmWorker = new GearmanWorker();
        $gmWorker->addServer($options['gearman']['host'], $options['gearman']['port']);

        foreach ($this->tasks as $name => $object) {
            $function = $options['namespace'] . '-' . $name;
            $task = function ($job) use ($name, $function, $object, $options) {
                if (@$options['debug'] === true)
                    echo "==> Running worker for: $function (PID " . getmypid() . ")" . PHP_EOL;

                $worker = clone $object;
                $data = json_decode($job->workload(), true);
                $worker->setData($data);

                if (@$options['debug'] !== true)
                    ob_start();
                $worker->run($this->exitRequested);
                if (@$options['debug'] !== true)
                    ob_end_clean();
            };
            $gmWorker->addFunction($function, $task);
        }

        while (true) {
            $dead = pcntl_waitpid(-1, $status, WNOHANG);
            while ($dead > 0) {
                if (@$options['debug'] === true)
                    echo "==> Worker PID $dead terminated" . PHP_EOL;

                $index = array_search($dead, $this->pids);
                if ($index !== false)
                    unset($this->pids[$index]); 

                $dead = pcntl_waitpid(-1, $status, WNOHANG);
            }

            while (count($this->pids) < $options['num_workers']) {
                $pid = pcntl_fork();
                if ($pid == 0) {
                    declare(ticks = 1);

                    $exitCallback = function ($signo) {
                        $this->exitRequested = true;
                    };

                    pcntl_signal(SIGTERM, $exitCallback);
                    pcntl_signal(SIGINT, $exitCallback);
                    pcntl_signal_dispatch();

                    $this->pids = [];
                    $gmWorker->setTimeout(1000);
                    while (!$this->exitRequested) {
                        $gmWorker->work();
                        $code = $gmWorker->returnCode();
                        switch ($code) {
                            case GEARMAN_TIMEOUT:
                                sleep(1);
                                break;
                            case GEARMAN_SUCCESS:
                                $this->exitRequested = true;
                                break;
                            default:
                                if (@$options['debug'] === true)
                                    echo "==> Worker failed: $code";
                                exit(1);
                        }
                    }
                    exit;
                } else if ($pid > 0) {
                    $this->pids[] = $pid;
                }
            }

            sleep(1);
        }
    }
813591
public function run()
    {

        try {
            // register shutdown handler
            register_shutdown_function($this->getDefaultShutdownMethod());

            // bootstrap the daemon
            $this->bootstrap();

            // synchronize the application instance and register the class loaders
            $application = $this->application;

            // mark the daemon as successfully shutdown
            $this->synchronized(function ($self) {
                $self->state = EnumState::get(EnumState::RUNNING);
            }, $this);

            // create local instances of the storages
            $messages = $this->messages;
            $priorityKey = $this->priorityKey;
            $jobsToExecute = $this->jobsToExecute;

            // load the maximum number of jobs to process in parallel
            $maximumJobsToProcess = $this->getManagerSettings()->getMaximumJobsToProcess();

            // initialize the arrays for the message states and the jobs executing
            $jobsExecuting = array();
            $messagesFailed = array();
            $retryCounter = array();
            $callbacksToExecute = array();

            // keep the daemon running
            while ($this->keepRunning()) {
                // iterate over all job wrappers
                foreach ($jobsToExecute as $jobWrapper) {
                    try {
                        // load the message
                        $message = $messages[$jobWrapper->jobId];

                        // check if we've a message found
                        if ($message instanceof MessageInterface) {
                            // check the message state
                            switch ($message->getState()->getState()) {

                                // message is active and ready to be processed
                                case StateActive::KEY:

                                    // set the new state now
                                    $message->setState(StateToProcess::get());

                                    break;

                                // message is paused or in progress
                                case StatePaused::KEY:

                                    // invoke the callbacks for the state
                                    if ($message->hasCallbacks($message->getState())) {
                                        $callbacksToExecute[] = new Callback(clone $message, $application);
                                    }

                                    // log a message that we've a message that has been paused
                                    \info(sprintf('Message %s has been paused', $message->getMessageId()));

                                    break;

                                case StateInProgress::KEY:

                                    // query whether or not the job is still available
                                    if (isset($jobsExecuting[$message->getMessageId()])) {
                                        // make sure the job has been finished
                                        if ($jobsExecuting[$message->getMessageId()] instanceof JobInterface && $jobsExecuting[$message->getMessageId()]->isFinished()) {
                                            // log a message that the job is still in progress
                                            \info(sprintf('Job %s has been finished', $message->getMessageId()));

                                            // set the new state now
                                            $message->setState($jobsExecuting[$message->getMessageId()]->getMessage()->getState());

                                        } else {
                                            // log a message that the job is still in progress
                                            \info(sprintf('Job %s is still in progress', $message->getMessageId()));
                                        }

                                    } else {
                                        // log a message that the job is still in progress
                                        \critical(sprintf('Message %s has been deleted, but should still be there', $message->getMessageId()));
                                    }

                                    break;

                                // message failed
                                case StateFailed::KEY:

                                    // remove the old job from the queue
                                    unset($jobsExecuting[$message->getMessageId()]);

                                    // query whether or not the message has to be processed again
                                    if (isset($messagesFailed[$message->getMessageId()]) && $message->getRetryCounter() > 0) {
                                        // query whether or not the message has to be processed now
                                        if ($messagesFailed[$message->getMessageId()] < time() && $retryCounter[$message->getMessageId()] < $message->getRetryCounter()) {
                                            // retry to process the message
                                            $message->setState(StateToProcess::get());

                                            // update the execution time and raise the retry counter
                                            $messagesFailed[$message->getMessageId()] = time() + $message->getRetryTimeout($retryCounter[$message->getMessageId()]);
                                            $retryCounter[$message->getMessageId()]++;

                                        } elseif ($messagesFailed[$message->getMessageId()] < time() && $retryCounter[$message->getMessageId()] === $message->getRetryCounter()) {
                                            // log a message that we've a message with a unknown state
                                            \critical(sprintf('Message %s finally failed after %d retries', $message->getMessageId(), $retryCounter[$message->getMessageId()]));

                                            // stop executing the job because we've reached the maximum number of retries
                                            unset($jobsToExecute[$messageId = $message->getMessageId()]);
                                            unset($messagesFailed[$messageId]);
                                            unset($retryCounter[$messageId]);

                                            // invoke the callbacks for the state
                                            if ($message->hasCallbacks($message->getState())) {
                                                $callbacksToExecute[] = new Callback(clone $message, $application);
                                            }

                                        } else {
                                            // wait for the next try here
                                        }

                                    } elseif (!isset($messagesFailed[$message->getMessageId()]) && $message->getRetryCounter() > 0) {
                                        // first retry, so we've to initialize the next execution time and the retry counter
                                        $retryCounter[$message->getMessageId()] = 0;
                                        $messagesFailed[$message->getMessageId()] = time() + $message->getRetryTimeout($retryCounter[$message->getMessageId()]);

                                    } else {
                                        // log a message that we've a message with a unknown state
                                        \critical(sprintf('Message %s failed with NO retries', $message->getMessageId()));

                                        // stop executing the job because we've reached the maximum number of retries
                                        unset($jobsToExecute[$messageId = $message->getMessageId()]);

                                        // invoke the callbacks for the state
                                        if ($message->hasCallbacks($message->getState())) {
                                            $callbacksToExecute[] = new Callback(clone $message, $application);
                                        }
                                    }

                                    break;

                                case StateToProcess::KEY:

                                    // count messages in queue
                                    $inQueue = sizeof($jobsExecuting);

                                    // we only process 200 jobs in parallel
                                    if ($inQueue < $maximumJobsToProcess) {
                                        // set the new message state now
                                        $message->setState(StateInProgress::get());

                                        // start the job and add it to the internal array
                                        $jobsExecuting[$message->getMessageId()] = new Job(clone $message, $application);

                                    } else {
                                        // log a message that queue is actually full
                                        \info(sprintf('Job queue full - (%d jobs/%d msg wait)', $inQueue, sizeof($messages)));

                                        // if the job queue is full, restart iteration to remove processed jobs from queue first
                                        continue 2;
                                    }

                                    break;

                                // message processing has been successfully processed
                                case StateProcessed::KEY:

                                    // invoke the callbacks for the state
                                    if ($message->hasCallbacks($message->getState())) {
                                        $callbacksToExecute[] = new Callback(clone $message, $application);
                                    }

                                    // remove the job from the queue with jobs that has to be executed
                                    unset($jobsToExecute[$messageId = $message->getMessageId()]);

                                    // also remove the job + the message from the queue
                                    unset($jobsExecuting[$messageId]);
                                    unset($messages[$messageId]);

                                    break;

                                // message is in an unknown state -> this is weired and should never happen!
                                case StateUnknown::KEY:

                                    // log a message that we've a message with a unknown state
                                    \critical(sprintf('Message %s has state %s', $message->getMessageId(), $message->getState()));

                                    // set new state now
                                    $message->setState(StateFailed::get());

                                    break;

                                // we don't know the message state -> this is weired and should never happen!
                                default:

                                    // set the failed message state
                                    $message->setState(StateFailed::get());

                                    // log a message that we've a message with an invalid state
                                    \critical(sprintf('Message %s has an invalid state', $message->getMessageId()));

                                    break;
                            }
                        }

                        // add the message back to the stack (because we've a copy here)
                        if (isset($messages[$message->getMessageId()])) {
                            $messages[$jobWrapper->jobId] = $message;
                        }

                        // catch all exceptions
                    } catch (\Exception $e) {
                        $application->getInitialContext()->getSystemLogger()->critical($e->__toString());
                    }

                    // reduce CPU load depending on queue priority
                    $this->iterate($this->getQueueTimeout());
                }

                // reduce CPU load after each iteration
                $this->iterate($this->getDefaultTimeout());

                // profile the size of the session pool
                if ($this->profileLogger) {
                    $this->profileLogger->debug(
                        sprintf(
                            'Processed queue worker with priority %s, size of queue size is: %d',
                            $priorityKey,
                            sizeof($jobsToExecute)
                        )
                    );
                }
            }

            // clean up the instances and free memory
            $this->cleanUp();

            // mark the daemon as successfully shutdown
            $this->synchronized(function ($self) {
                $self->state = EnumState::get(EnumState::SHUTDOWN);
            }, $this);

        } catch (\Exception $e) {
            \error($e->__toString());
        }
    }
243374
def _start_new_worker_process(self, server_socket):
        """"""
        from multiprocessing import Process
        p = Process(target=forked_child, args=self._get_child_args(server_socket))
        p.start()
        return p
839185
public function fork()
    {
        $pair = $this->pair();

        $pid = pcntl_fork();
        if ($pid < 0) {  // Failed fork
            throw new \RuntimeException('Failed to fork child process.');
        } elseif ($pid === 0) {  // is worker process
            fclose($pair[0]);
            foreach ($this->sockets as $socket) {
                fclose($socket);
            }
            $this->sockets = array();
            $this->loop($pair[1]);
            exit;
        }

        fclose($pair[1]);
        $this->sockets[$pid] = $pair[0];

        return $pid;
    }
748402
def start(self):
        """"""
        if self.working:
            return
        self.working = True
        for i in range(self.num_workers):
            w = threading.Thread(
                name="Worker Thread #{i}".format(i=i),
                target=self._worker,
                )
            w.daemon = True
            w.start()
            self.workers.append(w)
240465
protected function start()
    {
        $this->processes[] = $this->createProcess()->handleOutputUsing(function ($type, $line) {
            call_user_func($this->output, $type, $line);
        });

        return $this;
    }
1072749
public function actionStart()
    {
        if ($this->clearLogs) {
            if (file_exists(static::$logFile)) {
                unlink(static::$logFile);
            }
            if (file_exists(static::$errorLogFile)) {
                unlink(static::$errorLogFile);
            }
        }

        $message = 'Starting Yii 2 Daemon ' . $this->version . '... ';

        if ($this->_getPid() === false) {
            $this->_getWorkers();
            if (!static::$_workersData) {
                $message .= 'No tasks found. Stopping!';
                echo $message . PHP_EOL;
                $this->_log($message);
                return static::EXIT_CODE_ERROR;
            }
            if ($this->_meetRequerements) {
                pcntl_signal(SIGTERM, ['inpassor\daemon\Controller', 'signalHandler']);
                pcntl_signal(SIGINT, ['inpassor\daemon\Controller', 'signalHandler']);
                pcntl_signal(SIGCHLD, ['inpassor\daemon\Controller', 'signalHandler']);
            }
        } else {
            $message .= 'Service is already running!';
            echo $message . PHP_EOL;
            $this->_log($message);
            return static::EXIT_CODE_NORMAL;
        }

        $this->_pid = $this->_meetRequerements ? pcntl_fork() : 0;
        if ($this->_pid == -1) {
            $message .= 'Could not start service!';
            echo $message . PHP_EOL;
            $this->_log($message);
            return static::EXIT_CODE_ERROR;
        } elseif ($this->_pid) {
            file_put_contents($this->_pidFile, $this->_pid);
            return static::EXIT_CODE_NORMAL;
        }
        if ($this->_meetRequerements) {
            posix_setsid();
        }

        $message .= 'OK.';
        echo $message . PHP_EOL;
        $this->_log($message);

        if ($this->_meetRequerements) {
            declare(ticks=1);
        };

        $previousSec = null;

        while (!static::$_stop) {
            $currentSec = date('s');
            $tickPlus = $currentSec === $previousSec ? 0 : 1;
            if ($tickPlus) {
                foreach (static::$_workersData as $workerUid => $workerData) {
                    if ($workerData['tick'] >= $workerData['delay']) {
                        static::$_workersData[$workerUid]['tick'] = 0;
                        $pid = 0;
                        if ($this->_meetRequerements) {
                            if (!isset(static::$workersPids[$workerUid])) {
                                static::$workersPids[$workerUid] = [];
                            }
                            $pid = (count(static::$workersPids[$workerUid]) < $workerData['maxProcesses']) ? pcntl_fork() : -2;
                        }
                        if ($pid == -1) {
                            $this->_log('Could not launch worker "' . $workerUid . '"');
                        } elseif ($pid == -2) {
                            $this->_log('Max processes exceed for launch worker "' . $workerUid . '"');
                        } elseif ($pid) {
                            static::$workersPids[$workerUid][] = $pid;
                        } else {

                            $config = ArrayHelper::merge(static::$_workersConfig[$workerUid] ?? [], [
                                'uid' => $workerUid
                            ]);

                            /** @var \inpassor\daemon\Worker $worker */
                            $worker = \Yii::createObject($config);
                            $worker->run();

                            if ($this->_meetRequerements) {
                                return static::EXIT_CODE_NORMAL;
                            }
                        }
                    }
                    static::$_workersData[$workerUid]['tick'] += $tickPlus;
                }
            }
            usleep(500000);
            $previousSec = $currentSec;
        }
        return static::EXIT_CODE_NORMAL;
    }
218151
public static function init()
    {
        Daemon::$startTime = time();
        set_time_limit(0);

        Daemon::$defaultErrorLevel = error_reporting();
        Daemon::$restrictErrorControl = (bool)Daemon::$config->restricterrorcontrol->value;
        ob_start(['\PHPDaemon\Core\Daemon', 'outputFilter']);
        set_error_handler(['\PHPDaemon\Core\Daemon', 'errorHandler']);

        Daemon::checkSupports();

        Daemon::$initservervar = $_SERVER;
        Daemon::$masters = new Collection;
        Daemon::$shm_wstate = new ShmEntity(Daemon::$config->pidfile->value, Daemon::SHM_WSTATE_SIZE, 'wstate', true);
        Daemon::openLogs();
    }
330807
def start(self):
        
        with self._operational_lock:
            if self._thread is not None:
                raise ValueError("Dispatcher is already running.")

            flow_control = self._manager.flow_control
            worker = helper_threads.QueueCallbackWorker(
                self._queue,
                self.dispatch_callback,
                max_items=flow_control.max_request_batch_size,
                max_latency=flow_control.max_request_batch_latency,
            )
            # Create and start the helper thread.
            thread = threading.Thread(name=_CALLBACK_WORKER_NAME, target=worker)
            thread.daemon = True
            thread.start()
            _LOGGER.debug("Started helper thread %s", thread.name)
            self._thread = thread
561617
public function start()
    {
        $this->brokerModel->consume(
            $this->pushSettings->getInputQueue(),
            function (\AMQPEnvelope $envelope, \AMQPQueue $queue) {
                return $this->messageProcessor->process(
                    $envelope,
                    $queue,
                    $this->pushPipe,
                    $this->pushSettings->getErrorQueue(),
                    new ReceiveCancellationToken(),
                    new EndpointControlToken()
                );
            }
        );
    }
712999
protected function spawnWorkers($n)
    {
        if (FileSystem::$supported) {
            eio_event_loop();
        }
        $n = (int)$n;

        for ($i = 0; $i < $n; ++$i) {
            $thread = new Worker;
            $this->workers->push($thread);
            $this->callbacks->push(function ($self) use ($thread) {
                // @check - is it possible to run iterate of main event loop without child termination?
                $thread->start();
                $pid = $thread->getPid();
                if ($pid < 0) {
                    Daemon::$process->log('could not fork worker');
                } elseif ($pid === 0) { // worker
                    Daemon::log('Unexcepted execution return to outside of Thread->start()');
                    exit;
                }
            });
        }
        if ($n > 0) {
            $this->lastMpmActionTs = microtime(true);
            if (EventLoop::$instance) {
                EventLoop::$instance->interrupt();
            }
        }
        return true;
    }
186669
public synchronized void start() {
        if (!running) {
            checkState(timer == null);

            timer = new java.util.Timer(true); // use daemon thread internally
            schedulePurging(); // schedule timeout to purge cancelled tasks from the timer task queue

            running = true;
        }
    }
776845
public function run()
    {

        try {
            // register shutdown handler
            register_shutdown_function($this->getDefaultShutdownMethod());

            // bootstrap the daemon
            $this->bootstrap();

            // invoke the execute method
            try {
                $this->execute();
            } catch (\Exception $e) {
                $this->log(LogLevel::ERROR, $e->__toString());
            }

            // clean up the instances and free memory
            $this->cleanUp();

        } catch (\Exception $e) {
            $this->log(LogLevel::ERROR, $e->__toString());
        }
    }
1116669
public function init()
    {
        $req = $this;

        $job = $this->job = new \PHPDaemon\Core\ComplexJob(function () use ($req) { // called when job is done
            $req->wakeup(); // wake up the request immediately

        });

        $job('query', function ($name, $job) { // registering job named 'showvar'
            \PHPDaemon\Clients\DNS\Pool::getInstance()->get('phpdaemon.net', function ($response) use ($name, $job) {
                $job->setResult($name, $response);
            });
        });

        $job('resolve', function ($name, $job) { // registering job named 'showvar'
            \PHPDaemon\Clients\DNS\Pool::getInstance()->resolve('phpdaemon.net', function ($ip) use ($name, $job) {
                $job->setResult($name, ['phpdaemon.net resolved to' => $ip]);
            });
        });

        $job(); // let the fun begin

        $this->sleep(5, true); // setting timeout
    }
439063
public function run()
    {

        try {
            // register shutdown handler
            register_shutdown_function($this->getDefaultShutdownMethod());

            // bootstrap the daemon
            $this->bootstrap();

            // mark the daemon as successfully shutdown
            $this->synchronized(function ($self) {
                $self->state = EnumState::get(EnumState::RUNNING);
            }, $this);

            // keep the daemon running
            while ($this->keepRunning()) {
                try {
                    $this->iterate($this->getDefaultTimeout());
                } catch (\Exception $e) {
                    $this->log(LogLevel::ERROR, $e->__toString());
                }
            }

            // clean up the instances and free memory
            $this->cleanUp();

            // mark the daemon as successfully shutdown
            $this->synchronized(function ($self) {
                $self->state = EnumState::get(EnumState::SHUTDOWN);
            }, $this);

        } catch (\Exception $e) {
            $this->log(LogLevel::ERROR, $e->__toString());
        }
    }
703480
def start(self):
        
        self.broker.emit_before("worker_boot", self)

        worker_middleware = _WorkerMiddleware(self)
        self.broker.add_middleware(worker_middleware)
        for _ in range(self.worker_threads):
            self._add_worker()

        self.broker.emit_after("worker_boot", self)
398808
def start(self, *args, **kwargs):
        
        args = (self.counter,) + args
        thread = threading.Thread(
                target=self._work_callback,
                args=args, kwargs=kwargs
                )
        thread.setDaemon(self.daemon)
        thread.start()