Skip to content

Commit

Permalink
Support cancelling the activity on Ctrl+C (non-Windows)
Browse files Browse the repository at this point in the history
  • Loading branch information
pjcdawkins committed Dec 18, 2020
1 parent 2a893f5 commit 338221c
Showing 1 changed file with 63 additions and 4 deletions.
67 changes: 63 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,29 @@ 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);
}
$bar->clear();
$stdErr->write($stdErr->isDecorated() ? "\n\033[1A" : "\n");
$result = $this->cancel($activity, $stdErr);
if ($result) {
exit(1);
}
$sigintReceived = true;
$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 +190,40 @@ 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 {
try {
$activity->cancel();
} catch (BadResponseException $e) {
if ($e->getResponse() && $e->getResponse()->getStatusCode() === 400 && \strpos($e->getMessage(), 'cannot be cancelled in its current state')) {
$activity->refresh();
$stdErr->writeln(\sprintf('The activity cannot be cancelled in its current state (<error>%s</error>).', $activity->state));
return false;
}
throw $e;
}
} catch (\Exception $e) {
$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 +493,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 +506,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

0 comments on commit 338221c

Please sign in to comment.