Files
michaelschiemer/src/Application/LiveComponents/Dashboard/PerformanceMetricsComponent.php
Michael Schiemer 36ef2a1e2c
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
fix: Gitea Traefik routing and connection pool optimization
- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
2025-11-09 14:46:15 +01:00

140 lines
5.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Application\LiveComponents\Dashboard;
use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\Percentage;
use App\Framework\DateTime\Clock;
use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\Contracts\Pollable;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;
use App\Framework\Performance\MemoryMonitor;
/**
* Performance Metrics LiveComponent
*
* Displays real-time performance metrics:
* - Memory usage (current, peak, limit, percentage)
* - Load average
* - Execution time
* - OPCache statistics
*
* Polls every 3 seconds for real-time monitoring.
*/
#[LiveComponent('performance-metrics')]
final readonly class PerformanceMetricsComponent implements LiveComponentContract, Pollable
{
public function __construct(
public ComponentId $id,
public PerformanceMetricsState $state,
private MemoryMonitor $memoryMonitor,
private Clock $clock
) {}
public function getRenderData(): ComponentRenderData
{
// Initial poll if state is empty (lastUpdated is empty string)
$state = $this->state->lastUpdated === ''
? $this->poll()
: $this->state;
return new ComponentRenderData(
templatePath: 'livecomponent-performance-metrics',
data: [
// LiveComponent integration
'componentId' => $this->id->toString(),
'stateJson' => json_encode($state->toArray()),
'pollInterval' => $this->getPollInterval(),
// Component data
'currentMemory' => $state->currentMemory,
'peakMemory' => $state->peakMemory,
'memoryLimit' => $state->memoryLimit,
'memoryUsagePercentage' => $state->memoryUsagePercentage,
'loadAverage' => $state->loadAverage,
'executionTime' => $state->executionTime,
'includedFiles' => $state->includedFiles,
'opcacheEnabled' => $state->opcacheEnabled,
'opcacheMemoryUsage' => $state->opcacheMemoryUsage,
'opcacheCacheHits' => $state->opcacheCacheHits,
'opcacheMissRate' => $state->opcacheMissRate,
'lastUpdated' => $state->lastUpdated,
]
);
}
#[Action]
public function poll(): PerformanceMetricsState
{
// Get memory metrics
$currentMemory = $this->memoryMonitor->getCurrentMemory();
$peakMemory = $this->memoryMonitor->getPeakMemory();
$memoryLimit = $this->memoryMonitor->getMemoryLimit();
$usagePercentage = $this->memoryMonitor->getMemoryUsagePercentage();
// Get load average
$loadAverage = function_exists('sys_getloadavg') ? sys_getloadavg() : ['N/A', 'N/A', 'N/A'];
// Calculate execution time
$executionTime = number_format(
microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true)),
4
) . ' Sekunden';
// Get included files count
$includedFiles = count(get_included_files());
// Check OPCache status
$opcacheEnabled = function_exists('opcache_get_status');
$opcacheMemoryUsage = null;
$opcacheCacheHits = null;
$opcacheMissRate = null;
if ($opcacheEnabled) {
try {
$opcacheStatus = opcache_get_status(false);
if ($opcacheStatus !== false) {
$memoryUsed = Byte::fromBytes($opcacheStatus['memory_usage']['used_memory']);
$opcacheMemoryUsage = $memoryUsed->toHumanReadable();
$opcacheCacheHits = number_format($opcacheStatus['opcache_statistics']['hits']);
$hits = $opcacheStatus['opcache_statistics']['hits'];
$misses = $opcacheStatus['opcache_statistics']['misses'];
$total = $hits + $misses;
if ($total > 0) {
$missRate = Percentage::from(($misses / $total) * 100);
$opcacheMissRate = $missRate->format(2) . '%';
}
}
} catch (\Throwable) {
// Ignore errors
}
}
return $this->state->withMetrics(
currentMemory: $currentMemory->toHumanReadable(),
peakMemory: $peakMemory->toHumanReadable(),
memoryLimit: $memoryLimit->toHumanReadable(),
memoryUsagePercentage: (float) $usagePercentage->format(2),
loadAverage: $loadAverage,
executionTime: $executionTime,
includedFiles: $includedFiles,
opcacheEnabled: $opcacheEnabled,
opcacheMemoryUsage: $opcacheMemoryUsage,
opcacheCacheHits: $opcacheCacheHits,
opcacheMissRate: $opcacheMissRate
);
}
public function getPollInterval(): int
{
return 3000; // Poll every 3 seconds for real-time updates
}
}