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

- 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:
2025-11-09 14:46:15 +01:00
parent 85c369e846
commit 36ef2a1e2c
1366 changed files with 104925 additions and 28719 deletions

View File

@@ -0,0 +1,322 @@
/**
* Event Bus Module
*
* Provides centralized event system for cross-module communication.
* Features:
* - Pub/sub pattern
* - Namespaced events
* - Event filtering
* - Event history
* - Integration with LiveComponents
* - Integration with SSE
*/
import { Logger } from '../../core/logger.js';
/**
* EventBus - Centralized event system
*/
export class EventBus {
constructor(config = {}) {
this.config = {
enableHistory: config.enableHistory ?? false,
maxHistorySize: config.maxHistorySize || 100,
enableWildcards: config.enableWildcards ?? true,
...config
};
this.subscribers = new Map(); // Map<eventName, Set<callback>>
this.history = [];
this.middleware = [];
Logger.info('[EventBus] Initialized', {
enableHistory: this.config.enableHistory,
enableWildcards: this.config.enableWildcards
});
}
/**
* Create a new EventBus instance
*/
static create(config = {}) {
return new EventBus(config);
}
/**
* Subscribe to an event
*/
on(eventName, callback, options = {}) {
if (typeof callback !== 'function') {
throw new Error('Callback must be a function');
}
if (!this.subscribers.has(eventName)) {
this.subscribers.set(eventName, new Set());
}
const subscriber = {
callback,
once: options.once ?? false,
priority: options.priority || 0,
filter: options.filter || null
};
this.subscribers.get(eventName).add(subscriber);
// Sort by priority
const subscribers = Array.from(this.subscribers.get(eventName));
subscribers.sort((a, b) => b.priority - a.priority);
this.subscribers.set(eventName, new Set(subscribers));
// Return unsubscribe function
return () => {
const callbacks = this.subscribers.get(eventName);
if (callbacks) {
callbacks.delete(subscriber);
if (callbacks.size === 0) {
this.subscribers.delete(eventName);
}
}
};
}
/**
* Subscribe to an event (once)
*/
once(eventName, callback, options = {}) {
return this.on(eventName, callback, { ...options, once: true });
}
/**
* Unsubscribe from an event
*/
off(eventName, callback) {
if (!this.subscribers.has(eventName)) {
return;
}
const callbacks = this.subscribers.get(eventName);
for (const subscriber of callbacks) {
if (subscriber.callback === callback) {
callbacks.delete(subscriber);
break;
}
}
if (callbacks.size === 0) {
this.subscribers.delete(eventName);
}
}
/**
* Emit an event
*/
emit(eventName, data = null, options = {}) {
// Apply middleware
let processedData = data;
for (const middleware of this.middleware) {
const result = middleware(eventName, processedData, options);
if (result === null || result === false) {
return; // Middleware blocked the event
}
if (result !== undefined) {
processedData = result;
}
}
// Add to history
if (this.config.enableHistory) {
this.addToHistory(eventName, processedData, options);
}
// Get subscribers for exact event name
const subscribers = this.subscribers.get(eventName);
if (subscribers) {
this.notifySubscribers(subscribers, eventName, processedData, options);
}
// Handle wildcards
if (this.config.enableWildcards) {
this.handleWildcards(eventName, processedData, options);
}
// Handle namespaced events (e.g., 'user:created' triggers 'user:*')
this.handleNamespacedEvents(eventName, processedData, options);
Logger.debug('[EventBus] Event emitted', { eventName, data: processedData });
}
/**
* Notify subscribers
*/
notifySubscribers(subscribers, eventName, data, options) {
const subscribersArray = Array.from(subscribers);
for (const subscriber of subscribersArray) {
// Apply filter
if (subscriber.filter && !subscriber.filter(data, options)) {
continue;
}
try {
subscriber.callback(data, eventName, options);
} catch (error) {
Logger.error('[EventBus] Subscriber error', error);
}
// Remove if once
if (subscriber.once) {
subscribers.delete(subscriber);
}
}
}
/**
* Handle wildcard subscriptions
*/
handleWildcards(eventName, data, options) {
// Check for '*' subscribers
const wildcardSubscribers = this.subscribers.get('*');
if (wildcardSubscribers) {
this.notifySubscribers(wildcardSubscribers, eventName, data, options);
}
// Check for pattern matches (e.g., 'user:*' matches 'user:created')
for (const [pattern, subscribers] of this.subscribers.entries()) {
if (pattern.includes('*') && this.matchesPattern(eventName, pattern)) {
this.notifySubscribers(subscribers, eventName, data, options);
}
}
}
/**
* Handle namespaced events
*/
handleNamespacedEvents(eventName, data, options) {
const parts = eventName.split(':');
if (parts.length > 1) {
// Emit namespace wildcard (e.g., 'user:created' triggers 'user:*')
const namespacePattern = parts[0] + ':*';
const namespaceSubscribers = this.subscribers.get(namespacePattern);
if (namespaceSubscribers) {
this.notifySubscribers(namespaceSubscribers, eventName, data, options);
}
}
}
/**
* Check if event name matches pattern
*/
matchesPattern(eventName, pattern) {
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
return regex.test(eventName);
}
/**
* Add middleware
*/
use(middleware) {
if (typeof middleware !== 'function') {
throw new Error('Middleware must be a function');
}
this.middleware.push(middleware);
}
/**
* Add event to history
*/
addToHistory(eventName, data, options) {
this.history.push({
eventName,
data,
options,
timestamp: Date.now()
});
// Limit history size
if (this.history.length > this.config.maxHistorySize) {
this.history.shift();
}
}
/**
* Get event history
*/
getHistory(filter = null) {
if (!filter) {
return [...this.history];
}
if (typeof filter === 'string') {
// Filter by event name
return this.history.filter(event => event.eventName === filter);
}
if (typeof filter === 'function') {
// Custom filter function
return this.history.filter(filter);
}
return [];
}
/**
* Clear event history
*/
clearHistory() {
this.history = [];
}
/**
* Get all event names
*/
getEventNames() {
return Array.from(this.subscribers.keys());
}
/**
* Get subscriber count for an event
*/
getSubscriberCount(eventName) {
const subscribers = this.subscribers.get(eventName);
return subscribers ? subscribers.size : 0;
}
/**
* Remove all subscribers for an event
*/
removeAllListeners(eventName = null) {
if (eventName) {
this.subscribers.delete(eventName);
} else {
this.subscribers.clear();
}
}
/**
* Destroy event bus
*/
destroy() {
this.subscribers.clear();
this.history = [];
this.middleware = [];
Logger.info('[EventBus] Destroyed');
}
}
/**
* Create a global event bus instance
*/
let globalEventBus = null;
/**
* Get or create global event bus
*/
export function getGlobalEventBus(config = {}) {
if (!globalEventBus) {
globalEventBus = EventBus.create(config);
}
return globalEventBus;
}