Enhance error handling in artifact downloading process

This commit is contained in:
crazywhalecc
2026-04-16 14:08:06 +08:00
parent 182f4ee0d0
commit 3ff0742ff1
4 changed files with 46 additions and 5 deletions

View File

@@ -545,6 +545,7 @@ class ArtifactDownloader
} }
$try = false; $try = false;
$last_exception = null;
foreach ($queue as $item) { foreach ($queue as $item) {
try { try {
$instance = null; $instance = null;
@@ -605,6 +606,7 @@ class ArtifactDownloader
InteractiveTerm::finish("Download artifact {$artifact->getName()} {$item['display']} failed !", false); InteractiveTerm::finish("Download artifact {$artifact->getName()} {$item['display']} failed !", false);
InteractiveTerm::error("Failed message: {$e->getMessage()}", true); InteractiveTerm::error("Failed message: {$e->getMessage()}", true);
} }
$last_exception = $e;
$try = true; $try = true;
continue; continue;
} catch (ValidationException $e) { } catch (ValidationException $e) {
@@ -612,11 +614,12 @@ class ArtifactDownloader
InteractiveTerm::finish("Download artifact {$artifact->getName()} {$item['display']} failed !", false); InteractiveTerm::finish("Download artifact {$artifact->getName()} {$item['display']} failed !", false);
InteractiveTerm::error("Validation failed: {$e->getMessage()}"); InteractiveTerm::error("Validation failed: {$e->getMessage()}");
} }
$last_exception = $e;
break; break;
} }
} }
$vvv = !ApplicationContext::isDebug() ? "\nIf the problem persists, consider using `-v`, `-vv` or `-vvv` to enable verbose mode, or disable parallel downloading for more details." : ''; $vvv = !ApplicationContext::isDebug() ? "\nIf the problem persists, consider using `-v`, `-vv` or `-vvv` to enable verbose mode, or disable parallel downloading for more details." : '';
throw new DownloaderException("Download artifact '{$artifact->getName()}' failed. Please check your internet connection and try again.{$vvv}"); throw new DownloaderException("Download artifact '{$artifact->getName()}' failed. Please check your internet connection and try again.{$vvv}", previous: $last_exception, artifact_name: $artifact->getName());
} }
private function downloadWithConcurrency(): void private function downloadWithConcurrency(): void
@@ -672,8 +675,7 @@ class ArtifactDownloader
$artifact_name = $artifact->getName(); $artifact_name = $artifact->getName();
} }
$failed_downloads[] = ['artifact' => $artifact_name, 'error' => $e]; $failed_downloads[] = ['artifact' => $artifact_name, 'error' => $e];
InteractiveTerm::setMessage("[{$downloaded}/{$total}] Download failed: {$artifact_name}"); throw $e;
InteractiveTerm::advance();
} }
// remove from pool // remove from pool
unset($fiber_pool[$index]); unset($fiber_pool[$index]);

View File

@@ -10,4 +10,15 @@ namespace StaticPHP\Exception;
* This exception is used to indicate that a download operation has failed, * This exception is used to indicate that a download operation has failed,
* typically due to network issues, invalid URLs, or other related problems. * typically due to network issues, invalid URLs, or other related problems.
*/ */
class DownloaderException extends SPCException {} class DownloaderException extends SPCException
{
public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null, private readonly ?string $artifact_name = null)
{
parent::__construct($message, $code, $previous);
}
public function getArtifactName(): ?string
{
return $this->artifact_name;
}
}

View File

@@ -72,7 +72,7 @@ class ExceptionHandler
} }
} }
if (!ApplicationContext::isDebug()) { if (!ApplicationContext::isDebug()) {
self::logError('⚠ If you want to see more details in console, use `-vvv` option.'); self::logError('⚠ If you want to see more details in console, use `-v`, `-vv` or `-vvv` option.');
} }
return self::getReturnCode($e); return self::getReturnCode($e);
} }
@@ -232,6 +232,9 @@ class ExceptionHandler
if ($e instanceof ExecutionException) { if ($e instanceof ExecutionException) {
self::logError(''); self::logError('');
self::logError('Failed command: ' . ConsoleColor::gray($e->getExecutionCommand())); self::logError('Failed command: ' . ConsoleColor::gray($e->getExecutionCommand()));
if ($e->getCode() !== 0) {
self::logError(' - Exit code: ' . ConsoleColor::gray((string) $e->getCode()));
}
if ($cd = $e->getCd()) { if ($cd = $e->getCd()) {
self::logError(' - Command executed in: ' . ConsoleColor::gray($cd)); self::logError(' - Command executed in: ' . ConsoleColor::gray($cd));
} }
@@ -243,6 +246,26 @@ class ExceptionHandler
} }
} }
// get downloader info
if ($e instanceof DownloaderException) {
if ($artifact_name = $e->getArtifactName()) {
self::logError('Failed artifact: ' . ConsoleColor::gray($artifact_name));
}
$cause = $e->getPrevious();
if ($cause instanceof ExecutionException) {
self::logError('');
self::logError('Last failed command: ' . ConsoleColor::gray($cause->getExecutionCommand()));
if ($cause->getCode() !== 0) {
self::logError(' - Exit code: ' . ConsoleColor::gray((string) $cause->getCode()));
}
if ($cd = $cause->getCd()) {
self::logError(' - Command executed in: ' . ConsoleColor::gray($cd));
}
} elseif ($cause instanceof DownloaderException || $cause instanceof ValidationException) {
self::logError('Cause: ' . ConsoleColor::gray($cause->getMessage()));
}
}
// validation error // validation error
if ($e instanceof ValidationException) { if ($e instanceof ValidationException) {
self::logError('Failed validation module: ' . ConsoleColor::gray($e->getValidationModuleString())); self::logError('Failed validation module: ' . ConsoleColor::gray($e->getValidationModuleString()));

View File

@@ -174,6 +174,7 @@ abstract class Shell
$process = proc_open($cmd, $descriptors, $pipes, $cwd, env_vars: $env, options: PHP_OS_FAMILY === 'Windows' ? ['create_process_group' => true] : null); $process = proc_open($cmd, $descriptors, $pipes, $cwd, env_vars: $env, options: PHP_OS_FAMILY === 'Windows' ? ['create_process_group' => true] : null);
$output_value = ''; $output_value = '';
$process_completed = false;
try { try {
if (!is_resource($process)) { if (!is_resource($process)) {
throw new ExecutionException( throw new ExecutionException(
@@ -251,11 +252,15 @@ abstract class Shell
} }
} }
$process_completed = true;
return [ return [
'code' => $status['exitcode'], 'code' => $status['exitcode'],
'output' => $output_value, 'output' => $output_value,
]; ];
} finally { } finally {
if (!$process_completed && is_resource($process)) {
proc_terminate($process);
}
fclose($pipes[1]); fclose($pipes[1]);
fclose($pipes[2]); fclose($pipes[2]);
if ($file_res !== null) { if ($file_res !== null) {