Skip to content

Commit e9d99ca

Browse files
committed
Implement blocking http php server for master
1 parent 67f1c0d commit e9d99ca

File tree

13 files changed

+313
-172
lines changed

13 files changed

+313
-172
lines changed

Diff for: docs/UPGRADE.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Upgrade a major version
22

3+
## Upgrade from 7.x to 8.x
4+
5+
36
## Upgrade from 6.x to 7.x
47

58
### Step 1: Update deploy.php

Diff for: phpstan.neon

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ parameters:
1111
ignoreErrors:
1212
- "#^Constant DEPLOYER_VERSION not found\\.$#"
1313
- "#^Constant DEPLOYER_BIN not found\\.$#"
14+
- "#^Constant MASTER_ENDPOINT not found\\.$#"
1415
- "#CpanelPhp#"
1516
- "#AMQPMessage#"
1617

Diff for: src/Command/MainCommand.php

-2
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ protected function execute(Input $input, Output $output): int
130130

131131
if (!$plan) {
132132
$this->checkUpdates();
133-
$this->deployer->server->start();
134-
135133
if (!empty($skippedTasks)) {
136134
foreach ($skippedTasks as $taskName) {
137135
$output->writeln("<fg=yellow;options=bold>skip</> $taskName");

Diff for: src/Command/WorkerCommand.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
4545
if (!$output->isDecorated() && !defined('NO_ANSI')) {
4646
define('NO_ANSI', 'true');
4747
}
48-
$this->deployer->config->set('master_url', 'http://localhost:' . $input->getOption('port'));
48+
49+
define('MASTER_ENDPOINT', 'http://localhost:' . $input->getOption('port'));
4950

5051
$task = $this->deployer->tasks->get($input->getOption('task'));
5152
$host = $this->deployer->hosts->get($input->getOption('host'));

Diff for: src/Configuration/Configuration.php

+9-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
namespace Deployer\Configuration;
1212

13+
use Deployer\Deployer;
1314
use Deployer\Exception\ConfigurationException;
1415
use Deployer\Utility\Httpie;
1516

@@ -204,11 +205,13 @@ public function offsetUnset($offset): void
204205

205206
public function load(): void
206207
{
207-
if (!$this->has('master_url')) {
208+
if (!Deployer::isWorker()) {
208209
return;
209210
}
210211

211-
$values = Httpie::get($this->get('master_url') . '/load')
212+
$values = Httpie::get(MASTER_ENDPOINT . '/load')
213+
->setopt(CURLOPT_CONNECTTIMEOUT, 0)
214+
->setopt(CURLOPT_TIMEOUT, 0)
212215
->jsonBody([
213216
'host' => $this->get('alias'),
214217
])
@@ -218,11 +221,13 @@ public function load(): void
218221

219222
public function save(): void
220223
{
221-
if (!$this->has('master_url')) {
224+
if (!Deployer::isWorker()) {
222225
return;
223226
}
224227

225-
Httpie::get($this->get('master_url') . '/save')
228+
Httpie::get(MASTER_ENDPOINT . '/save')
229+
->setopt(CURLOPT_CONNECTTIMEOUT, 0)
230+
->setopt(CURLOPT_TIMEOUT, 0)
226231
->jsonBody([
227232
'host' => $this->get('alias'),
228233
'config' => $this->persist(),

Diff for: src/Deployer.php

+10-19
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
use Deployer\Configuration\Configuration;
2929
use Deployer\Executor\Master;
3030
use Deployer\Executor\Messenger;
31-
use Deployer\Executor\Server;
3231
use Deployer\Host\Host;
3332
use Deployer\Host\HostCollection;
3433
use Deployer\Host\Localhost;
@@ -37,7 +36,6 @@
3736
use Deployer\Logger\Handler\NullHandler;
3837
use Deployer\Logger\Logger;
3938
use Deployer\Selector\Selector;
40-
use Deployer\Task;
4139
use Deployer\Task\ScriptManager;
4240
use Deployer\Task\TaskCollection;
4341
use Deployer\Utility\Httpie;
@@ -66,7 +64,6 @@
6664
* @property ProcessRunner $processRunner
6765
* @property Task\ScriptManager $scriptManager
6866
* @property Selector $selector
69-
* @property Server $server
7067
* @property Master $master
7168
* @property Messenger $messenger
7269
* @property Messenger $logger
@@ -79,9 +76,8 @@ class Deployer extends Container
7976
{
8077
/**
8178
* Global instance of deployer. It's can be accessed only after constructor call.
82-
* @var Deployer
8379
*/
84-
private static $instance;
80+
private static Deployer $instance;
8581

8682
public function __construct(Application $console)
8783
{
@@ -163,17 +159,11 @@ public function __construct(Application $console)
163159
$this['messenger'] = function ($c) {
164160
return new Messenger($c['input'], $c['output'], $c['logger']);
165161
};
166-
$this['server'] = function ($c) {
167-
return new Server(
168-
$c['output'],
169-
$this,
170-
);
171-
};
172162
$this['master'] = function ($c) {
173163
return new Master(
164+
$c['hosts'],
174165
$c['input'],
175166
$c['output'],
176-
$c['server'],
177167
$c['messenger'],
178168
);
179169
};
@@ -351,21 +341,22 @@ public static function printException(OutputInterface $output, Throwable $except
351341

352342
public static function isWorker(): bool
353343
{
354-
return Deployer::get()->config->has('master_url');
344+
return defined('MASTER_ENDPOINT');
355345
}
356346

357347
/**
358348
* @param mixed ...$arguments
359349
* @return array|bool|string
360350
* @throws \Exception
361351
*/
362-
public static function proxyCallToMaster(Host $host, string $func, ...$arguments)
352+
public static function masterCall(Host $host, string $func, ...$arguments)
363353
{
364-
// As request to master will stop master permanently,
365-
// wait a little bit in order for periodic timer of
366-
// master gather worker outputs and print it to user.
367-
usleep(100000); // Sleep 100ms.
368-
return Httpie::get(get('master_url') . '/proxy')
354+
// As request to master will stop master permanently, wait a little bit
355+
// in order for ticker gather worker outputs and print it to user.
356+
usleep(100_000); // Sleep 100ms.
357+
358+
return Httpie::get(MASTER_ENDPOINT . '/proxy')
359+
->setopt(CURLOPT_CONNECTTIMEOUT, 0) // no timeout
369360
->setopt(CURLOPT_TIMEOUT, 0) // no timeout
370361
->jsonBody([
371362
'host' => $host->getAlias(),

Diff for: src/Executor/Master.php

+59-42
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
use Deployer\Component\Ssh\Client;
1414
use Deployer\Component\Ssh\IOArguments;
1515
use Deployer\Deployer;
16+
use Deployer\Exception\Exception;
1617
use Deployer\Host\Host;
18+
use Deployer\Host\HostCollection;
1719
use Deployer\Host\Localhost;
1820
use Deployer\Selector\Selector;
21+
use Deployer\Task\Context;
1922
use Deployer\Task\Task;
2023
use Symfony\Component\Console\Input\InputInterface;
2124
use Symfony\Component\Console\Output\OutputInterface;
@@ -32,40 +35,21 @@ function spinner(string $message = ''): string
3235

3336
class Master
3437
{
35-
/**
36-
* @var InputInterface
37-
*/
38-
private $input;
39-
40-
/**
41-
* @var OutputInterface
42-
*/
43-
private $output;
44-
45-
/**
46-
* @var Server
47-
*/
48-
private $server;
49-
50-
/**
51-
* @var Messenger
52-
*/
53-
private $messenger;
54-
55-
/**
56-
* @var false|string
57-
*/
58-
private $phpBin;
38+
private HostCollection $hosts;
39+
private InputInterface $input;
40+
private OutputInterface $output;
41+
private Messenger $messenger;
42+
private string|false $phpBin;
5943

6044
public function __construct(
45+
HostCollection $hosts,
6146
InputInterface $input,
6247
OutputInterface $output,
63-
Server $server,
6448
Messenger $messenger,
6549
) {
50+
$this->hosts = $hosts;
6651
$this->input = $input;
6752
$this->output = $output;
68-
$this->server = $server;
6953
$this->messenger = $messenger;
7054
$this->phpBin = (new PhpExecutableFinder())->find();
7155
}
@@ -182,43 +166,76 @@ private function runTask(Task $task, array $hosts): int
182166
return 0;
183167
}
184168

185-
$callback = function (string $output) {
186-
$output = preg_replace('/\n$/', '', $output);
187-
if (strlen($output) !== 0) {
188-
$this->output->writeln($output);
189-
}
190-
};
169+
$server = new Server('127.0.0.1', 0, $this->output);
191170

192171
/** @var Process[] $processes */
193172
$processes = [];
194173

195-
$this->server->loop->futureTick(function () use (&$processes, $hosts, $task) {
174+
$server->afterRun(function (int $port) use (&$processes, $hosts, $task) {
196175
foreach ($hosts as $host) {
197-
$processes[] = $this->createProcess($host, $task);
176+
$processes[] = $this->createProcess($host, $task, $port);
198177
}
199178

200179
foreach ($processes as $process) {
201180
$process->start();
202181
}
203182
});
204183

205-
$this->server->loop->addPeriodicTimer(0.03, function ($timer) use (&$processes, $callback) {
206-
$this->gatherOutput($processes, $callback);
184+
$echoCallback = function (string $output) {
185+
$output = preg_replace('/\n$/', '', $output);
186+
if (strlen($output) !== 0) {
187+
$this->output->writeln($output);
188+
}
189+
};
190+
191+
$server->ticker(function () use (&$processes, $server, $echoCallback) {
192+
$this->gatherOutput($processes, $echoCallback);
207193
if ($this->output->isDecorated() && !getenv('CI')) {
208194
$this->output->write(spinner());
209195
}
210196
if ($this->allFinished($processes)) {
211-
$this->server->loop->stop();
212-
$this->server->loop->cancelTimer($timer);
197+
$server->stop();
198+
}
199+
});
200+
201+
$server->router(function (string $path, array $payload) {
202+
switch ($path) {
203+
case '/load':
204+
['host' => $host] = $payload;
205+
206+
$host = $this->hosts->get($host);
207+
$config = $host->config()->persist();
208+
209+
return new Response(200, $config);
210+
211+
case '/save':
212+
['host' => $host, 'config' => $config] = $payload;
213+
214+
$host = $this->hosts->get($host);
215+
$host->config()->update($config);
216+
217+
return new Response(200, true);
218+
219+
case '/proxy':
220+
['host' => $host, 'func' => $func, 'arguments' => $arguments] = $payload;
221+
222+
Context::push(new Context($this->hosts->get($host)));
223+
$answer = call_user_func($func, ...$arguments);
224+
Context::pop();
225+
226+
return new Response(200, $answer);
227+
228+
default:
229+
return new Response(404, null);
213230
}
214231
});
215232

216-
$this->server->loop->run();
233+
$server->run();
217234

218235
if ($this->output->isDecorated() && !getenv('CI')) {
219236
$this->output->write(" \r"); // clear spinner
220237
}
221-
$this->gatherOutput($processes, $callback);
238+
$this->gatherOutput($processes, $echoCallback);
222239

223240
if ($this->cumulativeExitCode($processes) !== 0) {
224241
$this->messenger->endTask($task, true);
@@ -227,11 +244,11 @@ private function runTask(Task $task, array $hosts): int
227244
return $this->cumulativeExitCode($processes);
228245
}
229246

230-
protected function createProcess(Host $host, Task $task): Process
247+
protected function createProcess(Host $host, Task $task, int $port): Process
231248
{
232249
$command = [
233250
$this->phpBin, DEPLOYER_BIN,
234-
'worker', '--port', $this->server->getPort(),
251+
'worker', '--port', $port,
235252
'--task', $task,
236253
'--host', $host->getAlias(),
237254
];

Diff for: src/Executor/Response.php

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/* (c) Anton Medvedev <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace Deployer\Executor;
12+
13+
class Response
14+
{
15+
private int $status;
16+
private mixed $body;
17+
18+
public function __construct(int $status, mixed $body)
19+
{
20+
$this->status = $status;
21+
$this->body = $body;
22+
}
23+
24+
public function getStatus(): int
25+
{
26+
return $this->status;
27+
}
28+
29+
public function getBody(): mixed
30+
{
31+
return $this->body;
32+
}
33+
}

0 commit comments

Comments
 (0)