@casoon/auditmysite
Version:
Professional website analysis suite with robust accessibility testing, Core Web Vitals performance monitoring, SEO analysis, and content optimization insights. Features isolated browser contexts, retry mechanisms, and comprehensive API endpoints for profe
275 lines • 9.83 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParallelTestManager = void 0;
const event_driven_queue_1 = require("./event-driven-queue");
const logging_1 = require("../logging");
/**
* @deprecated ParallelTestManager is deprecated and will be removed in v3.0.0
*
* This class is replaced by the unified PageAnalysisEmitter system integrated into AccessibilityChecker.
* The new system provides better performance, consistent event handling, and integrated resource monitoring.
*
* MIGRATION GUIDE:
* ```typescript
* // OLD (deprecated)
* const manager = new ParallelTestManager({
* maxConcurrent: 3,
* onTestComplete: (url, result) => { ... }
* });
* await manager.runTests(urls);
*
* // NEW (recommended)
* const checker = new AccessibilityChecker({
* enableUnifiedEvents: true,
* enableComprehensiveAnalysis: true
* });
* checker.setUnifiedEventCallbacks({ onUrlCompleted: (url, result) => { ... } });
* await checker.testMultiplePagesParallel(urls, { maxConcurrent: 3 });
* ```
*/
class ParallelTestManager {
constructor(options = {}) {
this.isRunning = false;
this.startTime = null;
this.activeTests = new Map();
this.options = {
maxConcurrent: 3,
maxRetries: 3,
retryDelay: 1000,
// default to quiet unless explicitly verbose
verbose: false,
enableResourceMonitoring: true,
maxMemoryUsage: 512, // 512 MB
maxCpuUsage: 80, // 80%
...options
};
// Configure logger
logging_1.log.setVerbose(this.options.verbose || false);
// Initialize Event-Driven Queue with persistence support
this.queue = new event_driven_queue_1.EventDrivenQueue({
maxRetries: this.options.maxRetries,
maxConcurrent: this.options.maxConcurrent,
retryDelay: this.options.retryDelay,
enableEvents: true,
// Pass persistence options through
enablePersistence: this.options.enablePersistence,
stateAdapter: this.options.stateAdapter,
autoSave: this.options.autoSave,
autoSaveInterval: this.options.autoSaveInterval,
stateId: this.options.stateId,
resumable: this.options.resumable,
eventCallbacks: {
onUrlAdded: this.handleUrlAdded.bind(this),
onUrlStarted: this.handleUrlStarted.bind(this),
onUrlCompleted: this.handleUrlCompleted.bind(this),
onUrlFailed: this.handleUrlFailed.bind(this),
onUrlRetrying: this.handleUrlRetrying.bind(this),
onQueueEmpty: this.handleQueueEmpty.bind(this),
onProgressUpdate: this.handleProgressUpdate.bind(this),
onError: this.handleError.bind(this)
}
});
// Initialize Accessibility Checker - use provided instance (required)
if (!options.accessibilityChecker) {
throw new Error('AccessibilityChecker instance is required in ParallelTestManager options');
}
this.accessibilityChecker = options.accessibilityChecker;
}
async initialize() {
await this.accessibilityChecker.initialize();
logging_1.log.debug(`Parallel Test Manager initialized with ${this.options.maxConcurrent} concurrent workers`);
}
/**
* Resume tests from saved state
*/
async resumeFromState(stateId) {
if (!this.queue.isPersistenceEnabled()) {
throw new Error('Persistence is not enabled, cannot resume from state');
}
try {
await this.queue.resumeFromState({
stateId: stateId || this.options.stateId,
skipCompleted: true
});
logging_1.log.success(`Resumed from saved state: ${stateId || this.options.stateId}`);
}
catch (error) {
throw new Error(`Failed to resume from state: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Get the current state ID
*/
getStateId() {
return this.queue.getStateId();
}
/**
* Save current state
*/
async saveState() {
if (this.queue.isPersistenceEnabled()) {
await this.queue.saveState();
}
}
async runTests(urls) {
if (this.isRunning) {
throw new Error('Test manager is already running');
}
this.isRunning = true;
this.startTime = new Date();
this.activeTests.clear();
logging_1.log.info(`Analyzing ${urls.length} pages with ${this.options.maxConcurrent} parallel workers`);
logging_1.log.startProgress(urls.length, 'accessibility analysis');
// Add URLs to queue
this.queue.addUrls(urls);
// Event listeners for queue events
this.setupEventListeners();
// Start parallel test execution
await this.processQueue();
const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
const stats = this.queue.getStats();
const results = this.queue.getCompletedResults();
const errors = this.queue.getFailedResults();
this.isRunning = false;
return {
results,
stats,
duration,
errors
};
}
async processQueue() {
return new Promise((resolve, reject) => {
// Event-Listener für Queue-Ende
this.queue.onQueueEmpty(() => {
resolve();
});
// Event-Listener für Fehler
this.queue.onError((event) => {
reject(new Error(event.data.error));
});
// Starte Worker-Prozesse
this.startWorkers();
});
}
startWorkers() {
// Starte initiale Worker bis zur maxConcurrent-Grenze
for (let i = 0; i < this.options.maxConcurrent; i++) {
this.processNextUrl();
}
}
async processNextUrl() {
if (!this.isRunning)
return;
const queuedUrl = await this.queue.getNextUrl();
if (!queuedUrl)
return;
try {
// Resource-Monitoring
if (this.options.enableResourceMonitoring) {
this.checkResourceLimits();
}
// Test ausführen
const testPromise = this.accessibilityChecker.testPage(queuedUrl.url, this.options.testOptions);
this.activeTests.set(queuedUrl.url, testPromise);
const result = await testPromise;
this.queue.markCompleted(queuedUrl.url, result);
}
catch (error) {
this.queue.markFailed(queuedUrl.url, String(error));
}
finally {
this.activeTests.delete(queuedUrl.url);
// Starte nächsten Worker
this.processNextUrl();
}
}
checkResourceLimits() {
const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024; // MB
const cpuUsage = process.cpuUsage().user / 1000000; // Sekunden
if (memoryUsage > this.options.maxMemoryUsage) {
logging_1.log.warn(`High memory usage: ${memoryUsage.toFixed(2)} MB`);
// Optional: Queue pausieren oder Worker reduzieren
}
if (cpuUsage > this.options.maxCpuUsage) {
logging_1.log.warn(`High CPU usage: ${cpuUsage.toFixed(2)}s`);
// Optional: Queue pausieren oder Worker reduzieren
}
}
// Event Handler - Reduced logging for cleaner output
handleUrlAdded(url, priority) {
// Silent - no logging needed
}
handleUrlStarted(url) {
this.options.onTestStart?.(url);
}
handleUrlCompleted(url, result, duration) {
this.options.onTestComplete?.(url, result);
}
handleUrlFailed(url, error, attempts) {
this.options.onTestError?.(url, error);
}
handleUrlRetrying(url, attempts) {
// Silent retry - no logging needed for cleaner output
}
handleQueueEmpty() {
logging_1.log.completeProgress();
this.options.onQueueEmpty?.();
}
handleProgressUpdate(stats) {
logging_1.log.updateProgress(stats.completed, stats.failed);
this.options.onProgressUpdate?.(stats);
}
handleError(error) {
logging_1.log.error(`Queue error: ${error}`);
}
setupEventListeners() {
// Progress-Update-Interval
setInterval(() => {
const stats = this.queue.getStats();
this.handleProgressUpdate(stats);
}, 5000); // Update every 5 seconds instead of every second
}
// Public API
pause() {
this.queue.pause();
logging_1.log.info('Tests paused');
}
resume() {
this.queue.resume();
logging_1.log.info('Tests resumed');
this.startWorkers();
}
stop() {
this.isRunning = false;
this.queue.clear();
logging_1.log.info('Tests stopped');
}
getStats() {
return this.queue.getStats();
}
getActiveTests() {
return this.activeTests.size;
}
getQueueSize() {
return this.queue.getQueueSize();
}
setMaxConcurrent(max) {
this.queue.setMaxConcurrent(max);
logging_1.log.debug(`Max concurrent workers set to ${max}`);
}
// Resource Management
getMemoryUsage() {
return process.memoryUsage().heapUsed / 1024 / 1024;
}
getCpuUsage() {
return process.cpuUsage().user / 1000000;
}
// Cleanup
async cleanup() {
this.stop();
await this.accessibilityChecker.cleanup();
}
}
exports.ParallelTestManager = ParallelTestManager;
//# sourceMappingURL=parallel-test-manager.js.map