Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 59 additions & 4 deletions src/Service/ActivityMonitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Platformsh\Cli\Service;

use GuzzleHttp\Exception\BadResponseException;
use Platformsh\Client\Model\Activity;
use Platformsh\Client\Model\ActivityLog\LogItem;
use Platformsh\Client\Model\Project;
Expand Down Expand Up @@ -99,6 +100,27 @@ public function waitAndLog(Activity $activity, $pollInterval = 3, $timestamps =
return Helper::formatTime(time() - $startTime);
});
$bar->setFormat('[%bar%] %elapsed:6s% (%state%)');

// Set up cancellation for the activity on Ctrl+C.
if (\function_exists('\\pcntl_signal') && $activity->operationAvailable('cancel')) {
declare(ticks = 1);
$sigintReceived = false;
/** @noinspection PhpComposerExtensionStubsInspection */
\pcntl_signal(SIGINT, function () use ($activity, $stdErr, $bar, &$sigintReceived) {
if ($sigintReceived) {
exit(1);
}
$sigintReceived = true;
$bar->clear();
if ($this->cancel($activity, $stdErr)) {
exit(1);
}
$stdErr->writeln('');
$bar->advance();
});
$stdErr->writeln('Enter Ctrl+C once to cancel the activity (or twice to quit this command).');
}

$bar->start();

$logStream = $this->getLogStream($activity, $bar);
Expand Down Expand Up @@ -166,6 +188,38 @@ public function waitAndLog(Activity $activity, $pollInterval = 3, $timestamps =
return false;
}

/**
* Attempts to cancel the activity, catching and printing errors.
*
* @param Activity $activity
* @param OutputInterface $stdErr
*
* @return bool
*/
private function cancel(Activity $activity, OutputInterface $stdErr)
{
if (!$activity->operationAvailable('cancel')) {
$stdErr->writeln('The activity cannot be cancelled.');
return false;
}
$stdErr->writeln('Cancelling the activity...');
try {
$activity->cancel();
} catch (\Exception $e) {
if ($e instanceof BadResponseException
&& $e->getResponse() && $e->getResponse()->getStatusCode() === 400
&& \strpos($e->getMessage(), 'cannot be cancelled in its current state') !== false) {
$activity->refresh();
$stdErr->writeln(\sprintf('The activity cannot be cancelled in its current state (<error>%s</error>).', $activity->state));
return false;
}
$stdErr->writeln(\sprintf('Failed to cancel the activity: <error>%s</error>', $e->getMessage()));
return false;
}
$stdErr->writeln('The activity was successfully cancelled.');
return true;
}

/**
* Reads the log stream and returns LogItem objects.
*
Expand Down Expand Up @@ -435,11 +489,11 @@ private function getStart(Activity $activity) {
private function getLogStream(Activity $activity, ProgressBar $bar) {
$url = $activity->getLink('log');

// Try fetching the stream with a 10 second timeout per call, and a .5
// second interval between calls, for up to 2 minutes.
$readTimeout = 10;
$interval = .5;
// Try fetching the stream with an up to 10 second timeout per call,
// and a .5 second interval between calls, for up to 2 minutes.
$readTimeout = .5;
$stream = \fopen($url, 'r', false, $this->api->getStreamContext($readTimeout));
$interval = .5;
$start = \microtime(true);
while ($stream === false) {
if (\microtime(true) - $start > 120) {
Expand All @@ -448,6 +502,7 @@ private function getLogStream(Activity $activity, ProgressBar $bar) {
$bar->advance();
\usleep($interval * 1000000);
$bar->advance();
$readTimeout = $readTimeout >= 10 ? $readTimeout : $readTimeout + .5;
$stream = \fopen($url, 'r', false, $this->api->getStreamContext($readTimeout));
}
\stream_set_blocking($stream, 0);
Expand Down