/** * The daemon's main run method. It should not be necessary to override, * instead use the main(), iterate() and cleanup() methods to implement * the daemons custom functionality. * * @return void * @see \Thread::run() */ 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()); } }
/** * We process the messages/jobs here. * * @return void */ 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 $messageStates = array(); $jobsExecuting = 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) { // set the inital message state if not done if (isset($messageStates[$jobWrapper->jobId]) === false) { // initialize the default message state if ($state = $message->getState()) { $messageStates[$jobWrapper->jobId] = $state->getState(); } else { $messageStates[$jobWrapper->jobId] = StateUnknown::KEY; } } // check the message state switch ($messageStates[$jobWrapper->jobId]) { // message is active and ready to be processed case StateActive::KEY: // set the new state now $messageStates[$message->getMessageId()] = StateToProcess::KEY; break; // message is paused or in progress // message is paused or in progress case StatePaused::KEY: case StateInProgress::KEY: // make sure the job has been finished if (isset($jobsExecuting[$message->getMessageId()]) && $jobsExecuting[$message->getMessageId()] instanceof JobInterface && $jobsExecuting[$message->getMessageId()]->isFinished()) { // log a message that the job is still in progress $this->getApplication()->getInitialContext()->getSystemLogger()->info(sprintf('Job %s has been finished, remove it from job queue now', $message->getMessageId())); // set the new state now $messageStates[$message->getMessageId()] = StateProcessed::KEY; } else { // log a message that the job is still in progress $this->getApplication()->getInitialContext()->getSystemLogger()->debug(sprintf('Job %s is still in progress', $message->getMessageId())); } break; // message processing failed or has been successfully processed // message processing failed or has been successfully processed case StateFailed::KEY: case StateProcessed::KEY: // load the unique message-ID $messageId = $message->getMessageId(); // remove the job from the queue with jobs that has to be executed unset($jobsToExecute[$messageId]); // also remove the job unset($jobsExecuting[$messageId]); // finally, remove the message states and the message from the queue unset($messageStates[$messageId]); unset($messages[$messageId]); break; // message has to be processed now // message has to be processed now case StateToProcess::KEY: // count messages in queue $inQueue = sizeof($jobsExecuting); // we only process 200 jobs in parallel if ($inQueue < $maximumJobsToProcess) { // start the job and add it to the internal array $jobsExecuting[$message->getMessageId()] = new Job(clone $message, $application); // set the new state now $messageStates[$message->getMessageId()] = StateInProgress::KEY; } else { // log a message that queue is actually full $application->getInitialContext()->getSystemLogger()->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 is in an unknown state -> this is weired and should never happen! // message is in an unknown state -> this is weired and should never happen! case StateUnknown::KEY: // set new state now $messageStates[$message->getMessageId()] = StateFailed::KEY; // log a message that we've a message with a unknown state $this->getApplication()->getInitialContext()->getSystemLogger()->critical(sprintf('Message %s has state %s', $message->getMessageId(), StateFailed::KEY)); break; // we don't know the message state -> this is weired and should never happen! // we don't know the message state -> this is weired and should never happen! default: // set the failed message state $messageStates[$message->getMessageId()] = StateFailed::KEY; // log a message that we've a message with an invalid state $this->getApplication()->getInitialContext()->getSystemLogger()->critical(sprintf('Message %s has an invalid state', $message->getMessageId())); break; } } // 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) { $application->getInitialContext()->getSystemLogger()->error($e->__toString()); } }