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:
@@ -13,6 +13,8 @@
|
||||
*/
|
||||
|
||||
import { Core } from '../core.js';
|
||||
import { PerformanceProfiler, LiveComponentsProfiler } from '../performance-profiler/profiler.js';
|
||||
import { FlamegraphVisualizer, TimelineVisualizer } from '../performance-profiler/visualizer.js';
|
||||
|
||||
export class LiveComponentDevTools {
|
||||
constructor() {
|
||||
@@ -26,12 +28,21 @@ export class LiveComponentDevTools {
|
||||
this.domBadges = new Map(); // Track DOM badges for cleanup
|
||||
this.badgesEnabled = true; // Badge visibility toggle
|
||||
|
||||
// Performance profiling state
|
||||
// Performance profiling state - using PerformanceProfiler
|
||||
this.profiler = new PerformanceProfiler({
|
||||
enabled: true,
|
||||
maxSamples: 1000,
|
||||
samplingInterval: 10,
|
||||
autoStart: false
|
||||
});
|
||||
this.flamegraphVisualizer = null;
|
||||
this.timelineVisualizer = null;
|
||||
this.isRecording = false;
|
||||
this.performanceRecording = [];
|
||||
this.performanceRecording = []; // Legacy data for backward compatibility
|
||||
this.componentRenderTimes = new Map();
|
||||
this.actionExecutionTimes = new Map();
|
||||
this.memorySnapshots = [];
|
||||
this.componentProfilers = new Map(); // Track profilers for each component
|
||||
|
||||
this.overlay = null;
|
||||
this.isEnabled = this.checkIfEnabled();
|
||||
@@ -163,8 +174,14 @@ export class LiveComponentDevTools {
|
||||
<button class="lc-devtools__btn lc-devtools__btn--small" data-action="clear-performance">
|
||||
Clear
|
||||
</button>
|
||||
<button class="lc-devtools__btn lc-devtools__btn--small" data-action="export-performance">
|
||||
Export
|
||||
</button>
|
||||
</div>
|
||||
<div class="lc-devtools__metrics" data-content="performance">
|
||||
<div id="lc-flamegraph-container" style="margin-bottom: 16px;"></div>
|
||||
<div id="lc-timeline-container" style="margin-bottom: 16px;"></div>
|
||||
</div>
|
||||
<div class="lc-devtools__metrics" data-content="performance"></div>
|
||||
</div>
|
||||
|
||||
<div class="lc-devtools__pane" data-pane="network">
|
||||
@@ -500,6 +517,10 @@ export class LiveComponentDevTools {
|
||||
this.clearPerformanceData();
|
||||
});
|
||||
|
||||
this.overlay.querySelector('[data-action="export-performance"]')?.addEventListener('click', () => {
|
||||
this.exportPerformanceData();
|
||||
});
|
||||
|
||||
this.overlay.querySelector('[data-action="clear-network"]')?.addEventListener('click', () => {
|
||||
this.clearNetworkLog();
|
||||
});
|
||||
@@ -616,6 +637,11 @@ export class LiveComponentDevTools {
|
||||
pane.classList.toggle('lc-devtools__pane--active', pane.dataset.pane === tabName);
|
||||
});
|
||||
|
||||
// Initialize visualizers when switching to performance tab
|
||||
if (tabName === 'performance') {
|
||||
this.initializePerformanceVisualizers();
|
||||
}
|
||||
|
||||
// Refresh content for active tab
|
||||
this.refreshActiveTab();
|
||||
}
|
||||
@@ -956,14 +982,80 @@ export class LiveComponentDevTools {
|
||||
* Clear performance data
|
||||
*/
|
||||
clearPerformanceData() {
|
||||
// Clear profiler data
|
||||
this.profiler.clear();
|
||||
|
||||
// Clear legacy data
|
||||
this.performanceData = [];
|
||||
this.performanceRecording = [];
|
||||
this.componentRenderTimes.clear();
|
||||
this.actionExecutionTimes.clear();
|
||||
this.memorySnapshots = [];
|
||||
|
||||
// Clear visualizers
|
||||
if (this.flamegraphVisualizer) {
|
||||
this.flamegraphVisualizer.clear();
|
||||
}
|
||||
if (this.timelineVisualizer) {
|
||||
this.timelineVisualizer.clear();
|
||||
}
|
||||
|
||||
this.renderPerformanceData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Export performance data
|
||||
*/
|
||||
exportPerformanceData() {
|
||||
const status = this.profiler.getStatus();
|
||||
|
||||
if (status.measuresCount === 0 && status.marksCount === 0 && status.samplesCount === 0) {
|
||||
alert('No performance data to export. Start recording first.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Export Chrome DevTools trace format
|
||||
const traceData = this.profiler.exportToChromeTrace();
|
||||
|
||||
// Create download
|
||||
const blob = new Blob([JSON.stringify(traceData, null, 2)], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `livecomponent-performance-${Date.now()}.json`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
console.log('[LiveComponent DevTools] Performance data exported');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize performance visualizers
|
||||
*/
|
||||
initializePerformanceVisualizers() {
|
||||
const flamegraphContainer = this.overlay.querySelector('#lc-flamegraph-container');
|
||||
const timelineContainer = this.overlay.querySelector('#lc-timeline-container');
|
||||
|
||||
if (flamegraphContainer && !this.flamegraphVisualizer) {
|
||||
this.flamegraphVisualizer = new FlamegraphVisualizer(flamegraphContainer, {
|
||||
width: flamegraphContainer.clientWidth || 750,
|
||||
height: 300,
|
||||
barHeight: 20,
|
||||
colorScheme: 'category'
|
||||
});
|
||||
}
|
||||
|
||||
if (timelineContainer && !this.timelineVisualizer) {
|
||||
this.timelineVisualizer = new TimelineVisualizer(timelineContainer, {
|
||||
width: timelineContainer.clientWidth || 750,
|
||||
height: 200,
|
||||
trackHeight: 30
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle performance recording
|
||||
*/
|
||||
@@ -989,6 +1081,11 @@ export class LiveComponentDevTools {
|
||||
*/
|
||||
startPerformanceRecording() {
|
||||
console.log('[LiveComponent DevTools] Performance recording started');
|
||||
|
||||
// Start the profiler
|
||||
this.profiler.start();
|
||||
|
||||
// Clear legacy data
|
||||
this.performanceRecording = [];
|
||||
this.memorySnapshots = [];
|
||||
|
||||
@@ -1011,6 +1108,12 @@ export class LiveComponentDevTools {
|
||||
stopPerformanceRecording() {
|
||||
console.log('[LiveComponent DevTools] Performance recording stopped');
|
||||
|
||||
// Stop the profiler and get results
|
||||
const results = this.profiler.stop();
|
||||
if (results) {
|
||||
console.log('[LiveComponent DevTools] Performance results:', results);
|
||||
}
|
||||
|
||||
if (this.memorySnapshotInterval) {
|
||||
clearInterval(this.memorySnapshotInterval);
|
||||
}
|
||||
@@ -1027,6 +1130,31 @@ export class LiveComponentDevTools {
|
||||
* Record action execution for performance profiling
|
||||
*/
|
||||
recordActionExecution(componentId, actionName, duration, startTime, endTime) {
|
||||
// Use profiler marks and measures if recording
|
||||
if (this.profiler.isRecording) {
|
||||
// Create synthetic marks based on the actual times
|
||||
// Note: The profiler uses performance.now() internally, so we need to adjust
|
||||
const markStart = `action:${componentId}:${actionName}:start`;
|
||||
const markEnd = `action:${componentId}:${actionName}:end`;
|
||||
const measureName = `action:${componentId}:${actionName}`;
|
||||
|
||||
// Record start mark (using current time as reference)
|
||||
this.profiler.mark(markStart, {
|
||||
componentId,
|
||||
actionName,
|
||||
type: 'action',
|
||||
originalStartTime: startTime,
|
||||
originalEndTime: endTime
|
||||
});
|
||||
|
||||
// Record end mark immediately (profiler will calculate duration from marks)
|
||||
this.profiler.mark(markEnd);
|
||||
|
||||
// Create measure - the profiler will calculate duration from the marks
|
||||
this.profiler.measure(measureName, markStart, markEnd);
|
||||
}
|
||||
|
||||
// Legacy recording for backward compatibility
|
||||
this.performanceRecording.push({
|
||||
type: 'action',
|
||||
componentId,
|
||||
@@ -1054,8 +1182,30 @@ export class LiveComponentDevTools {
|
||||
* Record component render for performance profiling
|
||||
*/
|
||||
recordComponentRender(componentId, duration, startTime, endTime) {
|
||||
if (!this.isRecording) return;
|
||||
if (!this.isRecording && !this.profiler.isRecording) return;
|
||||
|
||||
// Use profiler marks and measures if recording
|
||||
if (this.profiler.isRecording) {
|
||||
const markStart = `render:${componentId}:start`;
|
||||
const markEnd = `render:${componentId}:end`;
|
||||
const measureName = `render:${componentId}`;
|
||||
|
||||
// Record start mark
|
||||
this.profiler.mark(markStart, {
|
||||
componentId,
|
||||
type: 'render',
|
||||
originalStartTime: startTime,
|
||||
originalEndTime: endTime
|
||||
});
|
||||
|
||||
// Record end mark immediately
|
||||
this.profiler.mark(markEnd);
|
||||
|
||||
// Create measure
|
||||
this.profiler.measure(measureName, markStart, markEnd);
|
||||
}
|
||||
|
||||
// Legacy recording for backward compatibility
|
||||
this.performanceRecording.push({
|
||||
type: 'render',
|
||||
componentId,
|
||||
@@ -1103,40 +1253,99 @@ export class LiveComponentDevTools {
|
||||
const container = this.overlay.querySelector('[data-content="performance"]');
|
||||
if (!container) return;
|
||||
|
||||
if (this.performanceRecording.length === 0 && this.memorySnapshots.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div style="color: #969696; text-align: center; padding: 40px;">
|
||||
// Get profiler status
|
||||
const status = this.profiler.getStatus();
|
||||
const hasData = status.samplesCount > 0 || status.marksCount > 0 || status.measuresCount > 0;
|
||||
const hasLegacyData = this.performanceRecording.length > 0 || this.memorySnapshots.length > 0;
|
||||
|
||||
// Initialize visualizers if not already done
|
||||
this.initializePerformanceVisualizers();
|
||||
|
||||
// Get containers for visualizers (they should already exist in the DOM)
|
||||
const flamegraphContainer = this.overlay.querySelector('#lc-flamegraph-container');
|
||||
const timelineContainer = this.overlay.querySelector('#lc-timeline-container');
|
||||
|
||||
if (!hasData && !hasLegacyData) {
|
||||
// Clear visualizers
|
||||
if (this.flamegraphVisualizer) {
|
||||
this.flamegraphVisualizer.clear();
|
||||
}
|
||||
if (this.timelineVisualizer) {
|
||||
this.timelineVisualizer.clear();
|
||||
}
|
||||
|
||||
// Show empty state but preserve visualizer containers
|
||||
const existingContent = container.querySelector('.lc-perf-empty-state');
|
||||
if (!existingContent) {
|
||||
const emptyState = document.createElement('div');
|
||||
emptyState.className = 'lc-perf-empty-state';
|
||||
emptyState.style.cssText = 'color: #969696; text-align: center; padding: 40px;';
|
||||
emptyState.innerHTML = `
|
||||
<p>No performance data recorded</p>
|
||||
<p style="font-size: 12px; margin-top: 12px;">Click "● Record" to start profiling</p>
|
||||
</div>
|
||||
`;
|
||||
`;
|
||||
container.insertBefore(emptyState, flamegraphContainer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '<div class="lc-performance-view" style="padding: 0;">';
|
||||
|
||||
// Performance Summary
|
||||
html += this.renderPerformanceSummary();
|
||||
|
||||
// Flamegraph
|
||||
html += this.renderFlamegraph();
|
||||
|
||||
// Timeline
|
||||
html += this.renderPerformanceTimeline();
|
||||
|
||||
// Memory Usage Chart
|
||||
if (this.memorySnapshots.length > 0) {
|
||||
html += this.renderMemoryChart();
|
||||
// Remove empty state if present
|
||||
const emptyState = container.querySelector('.lc-perf-empty-state');
|
||||
if (emptyState) {
|
||||
emptyState.remove();
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
container.innerHTML = html;
|
||||
// Render summary
|
||||
const summaryHtml = this.renderPerformanceSummary();
|
||||
|
||||
// Insert or update summary (before visualizer containers)
|
||||
const existingSummary = container.querySelector('.lc-perf-summary');
|
||||
if (existingSummary) {
|
||||
existingSummary.outerHTML = summaryHtml;
|
||||
} else {
|
||||
container.insertAdjacentHTML('afterbegin', summaryHtml);
|
||||
}
|
||||
|
||||
// Render flamegraph if we have data
|
||||
if (this.flamegraphVisualizer && hasData && flamegraphContainer) {
|
||||
const flamegraphData = this.profiler.generateFlamegraph();
|
||||
if (flamegraphData) {
|
||||
this.flamegraphVisualizer.render(flamegraphData);
|
||||
} else {
|
||||
this.flamegraphVisualizer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Render timeline if we have data
|
||||
if (this.timelineVisualizer && hasData && timelineContainer) {
|
||||
const timelineData = this.profiler.generateTimeline();
|
||||
if (timelineData && timelineData.length > 0) {
|
||||
this.timelineVisualizer.render(timelineData);
|
||||
} else {
|
||||
this.timelineVisualizer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Render legacy memory chart if available
|
||||
if (this.memorySnapshots.length > 0) {
|
||||
const existingMemoryChart = container.querySelector('.lc-memory-chart');
|
||||
const memoryChartHtml = this.renderMemoryChart();
|
||||
if (existingMemoryChart) {
|
||||
existingMemoryChart.outerHTML = memoryChartHtml;
|
||||
} else {
|
||||
container.insertAdjacentHTML('beforeend', memoryChartHtml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render performance summary
|
||||
*/
|
||||
renderPerformanceSummary() {
|
||||
const status = this.profiler.getStatus();
|
||||
const summary = this.profiler.generateSummary();
|
||||
|
||||
// Legacy data counts
|
||||
const actionCount = this.performanceRecording.filter(r => r.type === 'action').length;
|
||||
const renderCount = this.performanceRecording.filter(r => r.type === 'render').length;
|
||||
|
||||
@@ -1144,15 +1353,9 @@ export class LiveComponentDevTools {
|
||||
? this.performanceRecording
|
||||
.filter(r => r.type === 'action')
|
||||
.reduce((sum, r) => sum + r.duration, 0) / actionCount
|
||||
: 0;
|
||||
: (summary.avgDuration || 0);
|
||||
|
||||
const avgRenderTime = renderCount > 0
|
||||
? this.performanceRecording
|
||||
.filter(r => r.type === 'render')
|
||||
.reduce((sum, r) => sum + r.duration, 0) / renderCount
|
||||
: 0;
|
||||
|
||||
const totalDuration = this.performanceRecording.reduce((sum, r) => sum + r.duration, 0);
|
||||
const totalDuration = summary.totalDuration || this.performanceRecording.reduce((sum, r) => sum + r.duration, 0);
|
||||
|
||||
return `
|
||||
<div class="lc-perf-summary" style="padding: 16px; border-bottom: 1px solid #3c3c3c; background: #252526;">
|
||||
@@ -1160,18 +1363,18 @@ export class LiveComponentDevTools {
|
||||
<div style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; font-size: 12px;">
|
||||
<div>
|
||||
<div style="color: #858585; margin-bottom: 4px;">Total Events</div>
|
||||
<div style="color: #4ec9b0; font-size: 18px; font-weight: 600;">${this.performanceRecording.length}</div>
|
||||
<div style="color: #4ec9b0; font-size: 18px; font-weight: 600;">${status.timelineEventsCount || this.performanceRecording.length}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="color: #858585; margin-bottom: 4px;">Actions</div>
|
||||
<div style="color: #dcdcaa; font-size: 18px; font-weight: 600;">${actionCount}</div>
|
||||
<div style="color: #858585; margin-bottom: 4px;">Measures</div>
|
||||
<div style="color: #dcdcaa; font-size: 18px; font-weight: 600;">${status.measuresCount || actionCount}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="color: #858585; margin-bottom: 4px;">Renders</div>
|
||||
<div style="color: #569cd6; font-size: 18px; font-weight: 600;">${renderCount}</div>
|
||||
<div style="color: #858585; margin-bottom: 4px;">Samples</div>
|
||||
<div style="color: #569cd6; font-size: 18px; font-weight: 600;">${status.samplesCount}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="color: #858585; margin-bottom: 4px;">Avg Action</div>
|
||||
<div style="color: #858585; margin-bottom: 4px;">Avg Duration</div>
|
||||
<div style="color: #dcdcaa; font-size: 18px; font-weight: 600;">${avgActionTime.toFixed(2)}ms</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -1179,6 +1382,13 @@ export class LiveComponentDevTools {
|
||||
<div style="color: #f48771; font-size: 18px; font-weight: 600;">${totalDuration.toFixed(2)}ms</div>
|
||||
</div>
|
||||
</div>
|
||||
${summary.percentiles ? `
|
||||
<div style="margin-top: 12px; padding-top: 12px; border-top: 1px solid #3c3c3c; font-size: 11px; color: #858585;">
|
||||
<strong>Percentiles:</strong> P50: ${summary.percentiles.p50?.toFixed(2) || 'N/A'}ms |
|
||||
P90: ${summary.percentiles.p90?.toFixed(2) || 'N/A'}ms |
|
||||
P99: ${summary.percentiles.p99?.toFixed(2) || 'N/A'}ms
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user