125 lines
4 KiB
PHP
125 lines
4 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\IncidentActivity;
|
|
use App\Models\PaymentIncident;
|
|
use App\Models\ProviderUptimeLog;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class CheckPaymentUptime extends Command
|
|
{
|
|
protected $signature = 'payment:check-uptime';
|
|
|
|
protected $description = 'Prüft die Erreichbarkeit von PAYONE und legt bei Ausfall automatisch einen Incident an.';
|
|
|
|
/**
|
|
* @var array<string, string>
|
|
*/
|
|
private array $endpoints = [
|
|
'payone' => 'https://api.pay1.de/post-gateway/',
|
|
];
|
|
|
|
public function handle(): int
|
|
{
|
|
Log::channel('payment')->info('COMMAND [payment:check-uptime] started.');
|
|
|
|
foreach ($this->endpoints as $provider => $url) {
|
|
$this->checkProvider($provider, $url);
|
|
}
|
|
|
|
Log::channel('payment')->info('COMMAND [payment:check-uptime] finished.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
private function checkProvider(string $provider, string $url): void
|
|
{
|
|
$startMs = now()->valueOf();
|
|
|
|
try {
|
|
$response = Http::timeout(10)->head($url);
|
|
$responseTimeMs = now()->valueOf() - $startMs;
|
|
$isUp = $response->successful() || $response->status() < 500;
|
|
$errorMessage = $isUp ? null : 'HTTP '.$response->status();
|
|
} catch (\Exception $e) {
|
|
$responseTimeMs = now()->valueOf() - $startMs;
|
|
$isUp = false;
|
|
$errorMessage = $e->getMessage();
|
|
}
|
|
|
|
ProviderUptimeLog::create([
|
|
'provider' => $provider,
|
|
'is_up' => $isUp,
|
|
'response_time_ms' => (int) $responseTimeMs,
|
|
'error_message' => $errorMessage,
|
|
'checked_at' => now(),
|
|
]);
|
|
|
|
$status = $isUp ? 'UP' : 'DOWN';
|
|
$this->line("[{$provider}] {$status} ({$responseTimeMs}ms)");
|
|
Log::channel('payment')->info("[payment:check-uptime] {$provider} {$status}", [
|
|
'response_time_ms' => $responseTimeMs,
|
|
'error_message' => $errorMessage,
|
|
]);
|
|
|
|
if (! $isUp) {
|
|
$this->handleOutage($provider, $errorMessage);
|
|
} else {
|
|
$this->handleRecovery($provider);
|
|
}
|
|
}
|
|
|
|
private function handleOutage(string $provider, ?string $errorMessage): void
|
|
{
|
|
$incident = PaymentIncident::firstOrCreate(
|
|
[
|
|
'provider' => $provider,
|
|
'type' => 'outage',
|
|
'status' => 'open',
|
|
],
|
|
[
|
|
'title' => 'Automatisch: '.strtoupper($provider).' nicht erreichbar',
|
|
'description' => 'Uptime-Check hat einen Ausfall erkannt.',
|
|
'severity' => 'critical',
|
|
'detected_at' => now()->startOfHour(),
|
|
]
|
|
);
|
|
|
|
IncidentActivity::create([
|
|
'incident_id' => $incident->id,
|
|
'type' => 'note',
|
|
'title' => 'Uptime-Check: '.strtoupper($provider).' DOWN',
|
|
'content' => $errorMessage,
|
|
'author' => 'System',
|
|
]);
|
|
|
|
Log::channel('payment')->error("[payment:check-uptime] Outage-Incident #{$incident->id} für {$provider}.");
|
|
}
|
|
|
|
private function handleRecovery(string $provider): void
|
|
{
|
|
$openOutages = PaymentIncident::where('provider', $provider)
|
|
->where('type', 'outage')
|
|
->whereIn('status', ['open', 'in_progress'])
|
|
->get();
|
|
|
|
foreach ($openOutages as $incident) {
|
|
$incident->update([
|
|
'status' => 'resolved',
|
|
'resolved_at' => now(),
|
|
]);
|
|
|
|
IncidentActivity::create([
|
|
'incident_id' => $incident->id,
|
|
'type' => 'status_change',
|
|
'title' => 'Automatisch aufgelöst: '.strtoupper($provider).' ist wieder erreichbar',
|
|
'author' => 'System',
|
|
]);
|
|
|
|
Log::channel('payment')->info("[payment:check-uptime] Incident #{$incident->id} für {$provider} automatisch aufgelöst.");
|
|
}
|
|
}
|
|
}
|