/** * @param RuntimeInterface $runtime * @param ChannelCompositeInterface $composite * @param ConfigInterface $config */ private function registerRuntimeSupervision(RuntimeInterface $runtime, ChannelCompositeInterface $composite, ConfigInterface $config) { $timerCollection = new TimerCollection(); $channel = $composite->bus('slave'); $keepalive = $config->get('core.tolerance.child.keepalive'); $channel->on('disconnect', function ($alias) use($runtime, $keepalive, $timerCollection) { if ($keepalive <= 0) { return; } $timer = $runtime->loop()->addTimer($keepalive, function () use($alias, $runtime, $timerCollection) { $timerCollection->removeTimer($alias); $runtime->fail(new ChildUnresponsiveException("Child runtime [{$alias}] is unresponsive."), ['origin' => $alias]); }); $timerCollection->addTimer($alias, $timer); }); $channel->on('connect', function ($alias) use($timerCollection) { if (($timer = $timerCollection->getTimer($alias)) !== null) { $timer->cancel(); $timerCollection->removeTimer($alias); } }); $channel = $composite->bus('master'); $keepalive = $config->get('core.tolerance.parent.keepalive'); $channel->on('disconnect', function ($alias) use($runtime, $keepalive, $timerCollection) { if ($keepalive <= 0) { return; } $timer = $runtime->loop()->addTimer($keepalive, function () use($alias, $runtime, $timerCollection) { $timerCollection->removeTimer($alias); $runtime->fail(new ParentUnresponsiveException("Parent runtime [{$alias}] is unresponsive."), ['origin' => $alias]); }); $timerCollection->addTimer($alias, $timer); }); $channel->on('connect', function ($alias) use($timerCollection) { if (($timer = $timerCollection->getTimer($alias)) !== null) { $timer->cancel(); $timerCollection->removeTimer($alias); } }); }
/** * @param string $alias * @param string|null $name * @param int $flags * @return PromiseInterface */ public function createThread($alias, $name, $flags = Runtime::CREATE_DEFAULT) { if (isset($this->threads[$alias])) { if ($name === null) { $name = $this->threads[$alias]->name; } if ($flags === Runtime::CREATE_FORCE_SOFT) { $manager = $this; return $this->destroyThread($alias, Runtime::DESTROY_FORCE_SOFT)->then(function () use($manager, $alias, $name) { return $manager->createThread($alias, $name); }); } else { if ($flags === Runtime::CREATE_FORCE_HARD) { $manager = $this; return $this->destroyThread($alias, Runtime::DESTROY_FORCE_HARD)->then(function () use($manager, $alias, $name) { return $manager->createThread($alias, $name); }); } else { if ($flags === Runtime::CREATE_FORCE) { $manager = $this; return $this->destroyThread($alias, Runtime::DESTROY_FORCE)->then(function () use($manager, $alias, $name) { return $manager->createThread($alias, $name); }); } else { return Promise::doReject(new ResourceDefinedException('Thread with such alias already exists.')); } } } } else { if ($name === null) { return Promise::doReject(new InvalidArgumentException('Name of new thread cannot be null.')); } } $controller = new ThreadController(); $wrapper = new ThreadWrapper($controller, $this->runtime->core()->dataPath(), $this->runtime->alias(), $alias, $name); $wrapper->start(PTHREADS_INHERIT_ALL); $this->allocateThread($alias, $wrapper); $req = new Request($this->channel, $alias, new RuntimeCommand('cmd:ping')); return $req->call()->then(function () { return 'Thread has been created.'; }, function ($reason) use($alias) { $this->freeThread($alias); return $reason; }, function ($reason) use($alias) { $this->freeThread($alias); return $reason; }); }
/** * @param RuntimeInterface $runtime * @param ChannelBaseInterface $channel * @param string|null $receiver */ public function __construct(RuntimeInterface $runtime, ChannelBaseInterface $channel, $receiver = null) { $this->runtime = $runtime; $this->channel = $channel; $this->receiver = $receiver !== null ? $receiver : $runtime->parent(); }
/** * @param RuntimeInterface $runtime * @param ChannelCompositeInterface $composite * @param ChannelBaseInterface $console */ private function applyRootRouting(RuntimeInterface $runtime, ChannelCompositeInterface $composite, ChannelBaseInterface $console) { $master = $composite->bus('master'); $slave = $composite->bus('slave'); $router = $composite->input(); $router->addAnchor(new RuleHandler(function ($params) { return true; })); $router = $composite->output(); $router->addAnchor(function ($receiver, ChannelProtocolInterface $protocol, $flags, callable $success = null, callable $failure = null, callable $cancel = null, $timeout = 0.0) use($runtime, $slave, $console) { if ($receiver === Runtime::RESERVED_CONSOLE_CLIENT || $protocol->getDestination() === Runtime::RESERVED_CONSOLE_CLIENT) { $console->push(Runtime::RESERVED_CONSOLE_CLIENT, $protocol, $flags, $success, $failure, $cancel, $timeout); } else { if ($runtime->manager()->existsRuntime($receiver) || $slave->isConnected($receiver)) { $slave->push($receiver, $protocol, $flags, $success, $failure, $cancel, $timeout); } else { $slave->push($slave->getConnected(), $protocol, $flags, $success, $failure, $cancel, $timeout); } } }); $router = $master->input(); $router->addRule(new RuleMatchDestination($master->name()), new RuleHandler(function ($params) use($composite) { $this->executeProtocol($composite, $params['protocol']); })); $router->addAnchor(new RuleHandler(function ($params) use($slave) { $slave->push($slave->getConnected(), $params['protocol'], $params['flags']); })); $router = $slave->input(); $router->addRule(new RuleMatchDestination($slave->name()), new RuleHandler(function ($params) use($composite) { $this->executeProtocol($composite, $params['protocol']); })); $router->addAnchor(new RuleHandler(function ($params) use($runtime, $slave, $console) { $receiver = $params['alias']; $protocol = $params['protocol']; if ($receiver === Runtime::RESERVED_CONSOLE_CLIENT || $protocol->getDestination() === Runtime::RESERVED_CONSOLE_CLIENT) { $console->push(Runtime::RESERVED_CONSOLE_CLIENT, $protocol, $params['flags']); } else { $slave->push($slave->getConnected(), $params['protocol'], $params['flags']); } })); $router = $master->output(); $router->addAnchor(function ($sender, ChannelProtocolInterface $protocol, $flags, callable $success = null, callable $failure = null, callable $cancel = null, $timeout = 0.0) use($master) { $master->push($sender, $protocol, $flags, $success, $failure, $cancel, $timeout); }); $router = $slave->output(); $router->addAnchor(function ($sender, ChannelProtocolInterface $protocol, $flags, callable $success = null, callable $failure = null, callable $cancel = null, $timeout = 0.0) use($slave) { $slave->push($sender, $protocol, $flags, $success, $failure, $cancel, $timeout); }); }
/** * @param string $alias * @param string|null $name * @param int $flags * @return PromiseInterface */ public function createProcess($alias, $name, $flags = Runtime::CREATE_DEFAULT) { if (isset($this->processes[$alias])) { if ($name === null || $name === 'null') { $name = $this->processes[$alias]['name']; } if ($flags === Runtime::CREATE_DEFAULT && $this->processes[$alias]['verified'] === false) { $manager = $this; $req = new Request($this->channel, $alias, new RuntimeCommand('cmd:ping')); return $req->call()->then(function ($response) { return 'Process has been created.'; }, function () use($manager, $alias, $name) { return $manager->createProcess($alias, $name, Runtime::CREATE_FORCE_HARD); }); } else { if ($flags === Runtime::CREATE_FORCE_SOFT) { $manager = $this; return $this->destroyProcess($alias, Runtime::DESTROY_FORCE_SOFT)->then(function () use($manager, $alias, $name) { return $manager->createProcess($alias, $name); }); } else { if ($flags === Runtime::CREATE_FORCE_HARD) { $manager = $this; return $this->destroyProcess($alias, Runtime::DESTROY_FORCE_HARD)->then(function () use($manager, $alias, $name) { return $manager->createProcess($alias, $name); }); } else { if ($flags === Runtime::CREATE_FORCE) { $manager = $this; return $this->destroyProcess($alias, Runtime::DESTROY_FORCE)->then(function () use($manager, $alias, $name) { return $manager->createProcess($alias, $name); }); } else { return Promise::doReject(new ResourceDefinedException('Process with such alias already exists.')); } } } } } else { if ($name === null) { return Promise::doReject(new InvalidArgumentException('Name of new process cannot be null.')); } } $pid = $this->system->run($this->phpCommand('surume.process', [$this->runtime->alias(), $alias, $name])); if (!$this->system->existsPid($pid)) { return Promise::doReject(new ResourceDefinedException('Process could not be created.')); } if (!$this->allocateProcess($alias, $name, $pid)) { return Promise::doReject(new ResourceDefinedException('Process could not be created because of storage failure.')); } $req = new Request($this->channel, $alias, new RuntimeCommand('cmd:ping')); return $req->call()->then(function ($response) { return 'Process has been created.'; }, function ($reason) use($alias) { $this->freeProcess($alias); throw $reason; }, function ($reason) use($alias) { $this->freeProcess($alias); return $reason; }); }