fix: Gitea Traefik routing and connection pool optimization
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
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
- 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
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\ExceptionHandling\Middleware;
|
||||
|
||||
use App\Framework\ExceptionHandling\Scope\ErrorScope;
|
||||
use App\Framework\ExceptionHandling\Scope\ErrorScopeContext;
|
||||
use App\Framework\Http\HttpMiddleware;
|
||||
use App\Framework\Http\MiddlewareContext;
|
||||
use App\Framework\Http\MiddlewarePriority;
|
||||
use App\Framework\Http\MiddlewarePriorityAttribute;
|
||||
use App\Framework\Http\Next;
|
||||
use App\Framework\Http\RequestStateManager;
|
||||
|
||||
/**
|
||||
* Error Scope Middleware
|
||||
*
|
||||
* Automatically creates ErrorScope for HTTP requests to enable automatic
|
||||
* context enrichment for all exceptions thrown during request processing.
|
||||
*
|
||||
* Uses Value Objects (IpAddress, UserAgent, SessionId) where possible.
|
||||
* Scope is automatically cleaned up after request processing.
|
||||
*/
|
||||
#[MiddlewarePriorityAttribute(MiddlewarePriority::VERY_EARLY)]
|
||||
final readonly class ErrorScopeMiddleware implements HttpMiddleware
|
||||
{
|
||||
public function __construct(
|
||||
private ErrorScope $errorScope
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
||||
{
|
||||
// Create HTTP scope from request
|
||||
$scopeContext = $this->createHttpScope($context->request);
|
||||
|
||||
// Enter scope (returns token for cleanup)
|
||||
$token = $this->errorScope->enter($scopeContext);
|
||||
|
||||
try {
|
||||
// Process request through middleware chain
|
||||
$result = $next($context);
|
||||
|
||||
// Update scope with any additional context that became available
|
||||
// (e.g., user ID after authentication, route after routing)
|
||||
$this->updateScopeFromContext($scopeContext, $context, $stateManager);
|
||||
|
||||
return $result;
|
||||
} finally {
|
||||
// Always exit scope, even if exception occurred
|
||||
$this->errorScope->exit($token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create HTTP scope context from request
|
||||
*
|
||||
* Uses Value Objects where possible for type safety and validation.
|
||||
*/
|
||||
private function createHttpScope(\App\Framework\Http\Request $request): ErrorScopeContext
|
||||
{
|
||||
// Extract request ID (as string, since RequestId Value Object needs secret)
|
||||
$requestIdString = $request->id->toString();
|
||||
|
||||
// Extract IP address (as string, will be converted to Value Object in enrichContext)
|
||||
$ipAddressString = $request->server->getRemoteAddr()?->value ?? null;
|
||||
|
||||
// Extract user agent (as string, will be converted to Value Object in enrichContext)
|
||||
$userAgentString = $request->server->getUserAgent()?->value ?? null;
|
||||
|
||||
// Extract session ID (will be available after SessionMiddleware)
|
||||
$sessionId = null;
|
||||
if (property_exists($request, 'session') && $request->session !== null) {
|
||||
$sessionId = $request->session->id->toString();
|
||||
}
|
||||
|
||||
// Create scope context with metadata for later Value Object conversion
|
||||
return ErrorScopeContext::http(
|
||||
request: $request,
|
||||
operation: null, // Will be set by routing/controller
|
||||
component: null // Will be set by routing/controller
|
||||
)->addMetadata([
|
||||
'ip' => $ipAddressString,
|
||||
'user_agent' => $userAgentString,
|
||||
'request_id' => $requestIdString,
|
||||
'session_id' => $sessionId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update scope with additional context that became available during request processing
|
||||
*
|
||||
* E.g., user ID after authentication, route after routing
|
||||
*/
|
||||
private function updateScopeFromContext(
|
||||
ErrorScopeContext $scopeContext,
|
||||
MiddlewareContext $context,
|
||||
RequestStateManager $stateManager
|
||||
): void {
|
||||
// Get current scope (should be the one we just created)
|
||||
$currentScope = $this->errorScope->current();
|
||||
if ($currentScope === null || $currentScope->scopeId !== $scopeContext->scopeId) {
|
||||
return; // Scope changed or not found
|
||||
}
|
||||
|
||||
// Check if user ID became available (after authentication)
|
||||
$userId = $this->extractUserId($context, $stateManager);
|
||||
if ($userId !== null && $currentScope->userId === null) {
|
||||
// Create updated scope with user ID
|
||||
$updatedScope = $currentScope->withUserId($userId);
|
||||
// Replace current scope (exit and re-enter)
|
||||
$this->errorScope->exit();
|
||||
$this->errorScope->enter($updatedScope);
|
||||
}
|
||||
|
||||
// Check if route information became available (after routing)
|
||||
$route = $this->extractRouteInfo($context);
|
||||
if ($route !== null && $currentScope->operation === null) {
|
||||
$operation = "http.{$route['method']}.{$route['path']}";
|
||||
$updatedScope = $currentScope->withOperation($operation, $route['controller'] ?? null);
|
||||
$this->errorScope->exit();
|
||||
$this->errorScope->enter($updatedScope);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract user ID from context or state manager
|
||||
*/
|
||||
private function extractUserId(MiddlewareContext $context, RequestStateManager $stateManager): ?string
|
||||
{
|
||||
// Try to get from request attribute (set by auth middleware)
|
||||
if (method_exists($context->request, 'getAttribute')) {
|
||||
$user = $context->request->getAttribute('user');
|
||||
if ($user !== null && (is_object($user) && property_exists($user, 'id'))) {
|
||||
return (string) $user->id;
|
||||
}
|
||||
if (is_string($user)) {
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get from state manager
|
||||
try {
|
||||
$user = $stateManager->get('user');
|
||||
if ($user !== null && (is_object($user) && property_exists($user, 'id'))) {
|
||||
return (string) $user->id;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// Ignore - user not available
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract route information from context
|
||||
*/
|
||||
private function extractRouteInfo(MiddlewareContext $context): ?array
|
||||
{
|
||||
$request = $context->request;
|
||||
|
||||
// Try to get route from request attribute
|
||||
if (method_exists($request, 'getAttribute')) {
|
||||
$route = $request->getAttribute('route');
|
||||
if ($route !== null) {
|
||||
return [
|
||||
'method' => $request->method->value,
|
||||
'path' => $request->path,
|
||||
'controller' => is_object($route) ? get_class($route) : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: use request method and path
|
||||
return [
|
||||
'method' => $request->method->value,
|
||||
'path' => $request->path,
|
||||
'controller' => null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user