Files
michaelschiemer/src/Framework/ExceptionHandling/Scope/ErrorScope.php
Michael Schiemer 95147ff23e refactor(deployment): Remove WireGuard VPN dependency and restore public service access
Remove WireGuard integration from production deployment to simplify infrastructure:
- Remove docker-compose-direct-access.yml (VPN-bound services)
- Remove VPN-only middlewares from Grafana, Prometheus, Portainer
- Remove WireGuard middleware definitions from Traefik
- Remove WireGuard IPs (10.8.0.0/24) from Traefik forwarded headers

All monitoring services now publicly accessible via subdomains:
- grafana.michaelschiemer.de (with Grafana native auth)
- prometheus.michaelschiemer.de (with Basic Auth)
- portainer.michaelschiemer.de (with Portainer native auth)

All services use Let's Encrypt SSL certificates via Traefik.
2025-11-05 12:48:25 +01:00

136 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\ExceptionHandling\Scope;
use App\Framework\DI\Initializer;
use Fiber;
/**
* Error Scope Stack Manager
*
* Manages fiber-aware scope stack for error context enrichment.
* Each fiber has its own isolated scope stack.
*
* PHP 8.5+ with fiber isolation and automatic cleanup.
*/
final class ErrorScope
{
/** @var array<int, array<ErrorScopeContext>> Fiber-specific scope stacks */
private array $stack = [];
#[Initializer]
public static function initialize(): self
{
return new self();
}
/**
* Enter a new error scope
*
* @param ErrorScopeContext $context Scope context to enter
* @return int Token for leaving this scope (stack depth)
*/
public function enter(ErrorScopeContext $context): int
{
$id = $this->fiberId();
$this->stack[$id] ??= [];
$this->stack[$id][] = $context;
return count($this->stack[$id]);
}
/**
* Exit error scope(s)
*
* @param int $token Token from enter() - exits all scopes until this depth
*/
public function exit(int $token = 0): void
{
$id = $this->fiberId();
if (!isset($this->stack[$id])) {
return;
}
if ($token === 0) {
// Exit only the most recent scope
array_pop($this->stack[$id]);
} else {
// Exit all scopes until token depth
while (!empty($this->stack[$id]) && count($this->stack[$id]) >= $token) {
array_pop($this->stack[$id]);
}
}
// Cleanup empty stack
if (empty($this->stack[$id])) {
unset($this->stack[$id]);
}
}
/**
* Get current error scope context
*
* @return ErrorScopeContext|null Current scope or null if no scope active
*/
public function current(): ?ErrorScopeContext
{
$id = $this->fiberId();
$stack = $this->stack[$id] ?? [];
$current = end($stack);
return $current !== false ? $current : null;
}
/**
* Check if any scope is active
*/
public function hasScope(): bool
{
$id = $this->fiberId();
return !empty($this->stack[$id]);
}
/**
* Get scope depth (number of nested scopes)
*/
public function depth(): int
{
$id = $this->fiberId();
return count($this->stack[$id] ?? []);
}
/**
* Get fiber ID for isolation
*
* Returns 0 for main fiber, unique ID for each Fiber
*/
private function fiberId(): int
{
$fiber = Fiber::getCurrent();
return $fiber ? spl_object_id($fiber) : 0;
}
/**
* Clear all scopes (for testing/cleanup)
*/
public function clear(): void
{
$this->stack = [];
}
/**
* Get statistics for monitoring
*/
public function getStats(): array
{
return [
'active_fibers' => count($this->stack),
'total_scopes' => array_sum(array_map('count', $this->stack)),
'max_depth' => !empty($this->stack) ? max(array_map('count', $this->stack)) : 0,
];
}
}