@semiont/jobs 0.2.33 → 0.2.34-build.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { JobId, EntityType, GenerationContext } from '@semiont/
|
|
2
|
-
import { UserId, ResourceId, AnnotationId } from '@semiont/core';
|
|
1
|
+
import { JobId, UserId, ResourceId, EntityType, AnnotationId, GenerationContext } from '@semiont/core';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Job Queue Type Definitions - Discriminated Union Design
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/job-queue.ts","../src/job-worker.ts"],"names":["fs","jobQueue"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Job Queue Manager\n *\n * Filesystem-based job queue with atomic operations.\n * Jobs are stored in directories by status for easy polling.\n */\n\nimport { promises as fs } from 'fs';\nimport * as path from 'path';\nimport type { AnyJob, JobStatus, JobQueryFilters, CancelledJob } from './types';\nimport type { JobId } from '@semiont/api-client';\n\nexport interface JobQueueConfig {\n dataDir: string;\n}\n\nexport class JobQueue {\n private jobsDir: string;\n\n constructor(config: JobQueueConfig) {\n this.jobsDir = path.join(config.dataDir, 'jobs');\n }\n\n /**\n * Initialize job queue directories\n */\n async initialize(): Promise<void> {\n const statuses: JobStatus[] = ['pending', 'running', 'complete', 'failed', 'cancelled'];\n\n for (const status of statuses) {\n const dir = path.join(this.jobsDir, status);\n await fs.mkdir(dir, { recursive: true });\n }\n\n console.log('[JobQueue] Initialized job directories');\n }\n\n /**\n * Create a new job\n */\n async createJob(job: AnyJob): Promise<void> {\n const jobPath = this.getJobPath(job.metadata.id, job.status);\n await fs.writeFile(jobPath, JSON.stringify(job, null, 2), 'utf-8');\n console.log(`[JobQueue] Created job ${job.metadata.id} with status ${job.status}`);\n }\n\n /**\n * Get a job by ID (searches all status directories)\n */\n async getJob(jobId: JobId): Promise<AnyJob | null> {\n const statuses: JobStatus[] = ['pending', 'running', 'complete', 'failed', 'cancelled'];\n\n for (const status of statuses) {\n const jobPath = this.getJobPath(jobId, status);\n try {\n const content = await fs.readFile(jobPath, 'utf-8');\n return JSON.parse(content) as AnyJob;\n } catch (error) {\n // File doesn't exist in this status directory, try next\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Update a job (atomic: delete old, write new)\n */\n async updateJob(job: AnyJob, oldStatus?: JobStatus): Promise<void> {\n // If oldStatus provided, delete from old location\n if (oldStatus && oldStatus !== job.status) {\n const oldPath = this.getJobPath(job.metadata.id, oldStatus);\n try {\n await fs.unlink(oldPath);\n } catch (error) {\n // Ignore if file doesn't exist\n }\n }\n\n // Write to new location\n const newPath = this.getJobPath(job.metadata.id, job.status);\n await fs.writeFile(newPath, JSON.stringify(job, null, 2), 'utf-8');\n\n if (oldStatus && oldStatus !== job.status) {\n console.log(`[JobQueue] Moved job ${job.metadata.id} from ${oldStatus} to ${job.status}`);\n } else {\n console.log(`[JobQueue] Updated job ${job.metadata.id} (status: ${job.status})`);\n }\n }\n\n /**\n * Poll for next pending job (FIFO)\n */\n async pollNextPendingJob(): Promise<AnyJob | null> {\n const pendingDir = path.join(this.jobsDir, 'pending');\n\n try {\n const files = await fs.readdir(pendingDir);\n\n if (files.length === 0) {\n return null;\n }\n\n // Sort by filename (job IDs have timestamps via nanoid)\n files.sort();\n\n const jobFile = files[0]!;\n const jobPath = path.join(pendingDir, jobFile);\n\n const content = await fs.readFile(jobPath, 'utf-8');\n return JSON.parse(content) as AnyJob;\n } catch (error) {\n console.error('[JobQueue] Error polling pending jobs:', error);\n return null;\n }\n }\n\n /**\n * List jobs with filters\n */\n async listJobs(filters: JobQueryFilters = {}): Promise<AnyJob[]> {\n const jobs: AnyJob[] = [];\n\n // Determine which status directories to scan\n const statuses: JobStatus[] = filters.status\n ? [filters.status]\n : ['pending', 'running', 'complete', 'failed', 'cancelled'];\n\n for (const status of statuses) {\n const statusDir = path.join(this.jobsDir, status);\n\n try {\n const files = await fs.readdir(statusDir);\n\n for (const file of files) {\n const jobPath = path.join(statusDir, file);\n const content = await fs.readFile(jobPath, 'utf-8');\n const job = JSON.parse(content) as AnyJob;\n\n // Apply filters\n if (filters.type && job.metadata.type !== filters.type) continue;\n if (filters.userId && job.metadata.userId !== filters.userId) continue;\n\n jobs.push(job);\n }\n } catch (error) {\n // Directory might not exist yet\n continue;\n }\n }\n\n // Sort by created descending (newest first)\n jobs.sort((a, b) => new Date(b.metadata.created).getTime() - new Date(a.metadata.created).getTime());\n\n // Apply pagination\n const offset = filters.offset || 0;\n const limit = filters.limit || 100;\n\n return jobs.slice(offset, offset + limit);\n }\n\n /**\n * Cancel a job\n */\n async cancelJob(jobId: JobId): Promise<boolean> {\n const job = await this.getJob(jobId);\n\n if (!job) {\n return false;\n }\n\n // Can only cancel pending or running jobs\n if (job.status !== 'pending' && job.status !== 'running') {\n return false;\n }\n\n const oldStatus = job.status;\n\n // Create cancelled job with proper structure\n const cancelledJob: CancelledJob<any> = {\n status: 'cancelled',\n metadata: job.metadata,\n params: job.status === 'pending' ? job.params : job.params,\n startedAt: job.status === 'running' ? job.startedAt : undefined,\n completedAt: new Date().toISOString(),\n };\n\n await this.updateJob(cancelledJob, oldStatus);\n return true;\n }\n\n /**\n * Clean up old completed/failed jobs (older than retention period)\n */\n async cleanupOldJobs(retentionHours: number = 24): Promise<number> {\n const cutoffTime = Date.now() - (retentionHours * 60 * 60 * 1000);\n let deletedCount = 0;\n\n const cleanupStatuses: JobStatus[] = ['complete', 'failed', 'cancelled'];\n\n for (const status of cleanupStatuses) {\n const statusDir = path.join(this.jobsDir, status);\n\n try {\n const files = await fs.readdir(statusDir);\n\n for (const file of files) {\n const jobPath = path.join(statusDir, file);\n const content = await fs.readFile(jobPath, 'utf-8');\n const job = JSON.parse(content) as AnyJob;\n\n if (job.status === 'complete' || job.status === 'failed' || job.status === 'cancelled') {\n const completedTime = new Date(job.completedAt).getTime();\n\n if (completedTime < cutoffTime) {\n await fs.unlink(jobPath);\n deletedCount++;\n }\n }\n }\n } catch (error) {\n console.error(`[JobQueue] Error cleaning up ${status} jobs:`, error);\n }\n }\n\n if (deletedCount > 0) {\n console.log(`[JobQueue] Cleaned up ${deletedCount} old jobs`);\n }\n\n return deletedCount;\n }\n\n /**\n * Get job file path\n */\n private getJobPath(jobId: JobId, status: JobStatus): string {\n return path.join(this.jobsDir, status, `${jobId}.json`);\n }\n\n /**\n * Get statistics about the queue\n */\n async getStats(): Promise<{\n pending: number;\n running: number;\n complete: number;\n failed: number;\n cancelled: number;\n }> {\n const stats = {\n pending: 0,\n running: 0,\n complete: 0,\n failed: 0,\n cancelled: 0\n };\n\n const statuses: JobStatus[] = ['pending', 'running', 'complete', 'failed', 'cancelled'];\n\n for (const status of statuses) {\n const statusDir = path.join(this.jobsDir, status);\n\n try {\n const files = await fs.readdir(statusDir);\n stats[status] = files.length;\n } catch (error) {\n // Directory might not exist yet\n stats[status] = 0;\n }\n }\n\n return stats;\n }\n}\n\n// Singleton instance\nlet jobQueue: JobQueue | null = null;\n\nexport function getJobQueue(): JobQueue {\n if (!jobQueue) {\n throw new Error('JobQueue not initialized. Call initializeJobQueue() first.');\n }\n return jobQueue;\n}\n\nexport async function initializeJobQueue(config: JobQueueConfig): Promise<JobQueue> {\n jobQueue = new JobQueue(config);\n await jobQueue.initialize();\n return jobQueue;\n}\n","/**\n * Job Worker Base Class\n *\n * Abstract worker that polls the job queue and processes jobs.\n * Subclasses implement specific job processing logic.\n */\n\nimport type { AnyJob, RunningJob, CompleteJob, FailedJob, PendingJob } from './types';\nimport type { JobQueue } from './job-queue';\n\nexport abstract class JobWorker {\n private running = false;\n private currentJob: AnyJob | null = null;\n private pollIntervalMs: number;\n private errorBackoffMs: number;\n protected jobQueue: JobQueue;\n\n constructor(\n jobQueue: JobQueue,\n pollIntervalMs: number = 1000,\n errorBackoffMs: number = 5000\n ) {\n this.jobQueue = jobQueue;\n this.pollIntervalMs = pollIntervalMs;\n this.errorBackoffMs = errorBackoffMs;\n }\n\n /**\n * Start the worker (polls queue in loop)\n */\n async start(): Promise<void> {\n this.running = true;\n console.log(`[${this.getWorkerName()}] Started`);\n\n while (this.running) {\n try {\n const job = await this.pollNextJob();\n\n if (job) {\n await this.processJob(job);\n } else {\n // No jobs available, wait before polling again\n await this.sleep(this.pollIntervalMs);\n }\n } catch (error) {\n console.error(`[${this.getWorkerName()}] Error in main loop:`, error);\n // Back off on error to avoid tight error loops\n await this.sleep(this.errorBackoffMs);\n }\n }\n\n console.log(`[${this.getWorkerName()}] Stopped`);\n }\n\n /**\n * Stop the worker (graceful shutdown)\n */\n async stop(): Promise<void> {\n console.log(`[${this.getWorkerName()}] Stopping...`);\n this.running = false;\n\n // Wait for current job to finish (with timeout)\n const timeout = 60000; // 60 seconds\n const startTime = Date.now();\n\n while (this.currentJob && (Date.now() - startTime) < timeout) {\n await this.sleep(100);\n }\n\n if (this.currentJob) {\n console.warn(`[${this.getWorkerName()}] Forced shutdown while processing job ${this.currentJob.metadata.id}`);\n }\n }\n\n /**\n * Poll for next job to process\n */\n private async pollNextJob(): Promise<AnyJob | null> {\n const job = await this.jobQueue.pollNextPendingJob();\n\n if (job && this.canProcessJob(job)) {\n return job;\n }\n\n return null;\n }\n\n /**\n * Process a job (handles state transitions and error handling)\n */\n private async processJob(job: AnyJob): Promise<void> {\n this.currentJob = job;\n\n try {\n // Only process pending jobs\n if (job.status !== 'pending') {\n console.warn(`[${this.getWorkerName()}] Skipping non-pending job ${job.metadata.id}`);\n return;\n }\n\n // Create running job\n const runningJob: RunningJob<any, any> = {\n status: 'running',\n metadata: job.metadata,\n params: job.params,\n startedAt: new Date().toISOString(),\n progress: {}, // Initialize with empty progress\n };\n\n await this.jobQueue.updateJob(runningJob, 'pending');\n\n console.log(`[${this.getWorkerName()}] 🔄 Processing job ${job.metadata.id} (type: ${job.metadata.type})`);\n\n // Execute job-specific logic (passing running job) and get result\n const result = await this.executeJob(runningJob);\n\n // Allow subclasses to emit completion events with result data\n await this.emitCompletionEvent(runningJob, result);\n\n // Move to complete state with result\n const completeJob: CompleteJob<any, any> = {\n status: 'complete',\n metadata: runningJob.metadata,\n params: runningJob.params,\n startedAt: runningJob.startedAt,\n completedAt: new Date().toISOString(),\n result: result ?? {}, // Use returned result or empty object\n };\n\n await this.jobQueue.updateJob(completeJob, 'running');\n\n console.log(`[${this.getWorkerName()}] ✅ Job ${job.metadata.id} completed successfully`);\n\n } catch (error) {\n await this.handleJobFailure(job, error);\n } finally {\n this.currentJob = null;\n }\n }\n\n /**\n * Handle job failure (retry or move to failed)\n */\n protected async handleJobFailure(job: AnyJob, error: any): Promise<void> {\n const updatedMetadata = {\n ...job.metadata,\n retryCount: job.metadata.retryCount + 1,\n };\n\n if (updatedMetadata.retryCount < updatedMetadata.maxRetries) {\n console.log(`[${this.getWorkerName()}] Job ${job.metadata.id} failed, will retry (${updatedMetadata.retryCount}/${updatedMetadata.maxRetries})`);\n console.log(`[${this.getWorkerName()}] Error:`, error);\n\n // Move back to pending for retry\n const retryJob: PendingJob<any> = {\n status: 'pending',\n metadata: updatedMetadata,\n params: job.status === 'pending' ? job.params : job.params,\n };\n\n await this.jobQueue.updateJob(retryJob, job.status);\n\n } else {\n console.error(`[${this.getWorkerName()}] ❌ Job ${job.metadata.id} failed permanently after ${updatedMetadata.retryCount} retries`);\n console.error(`[${this.getWorkerName()}] Error:`, error);\n\n // Move to failed state\n const failedJob: FailedJob<any> = {\n status: 'failed',\n metadata: updatedMetadata,\n params: job.status === 'pending' ? job.params : job.params,\n startedAt: job.status === 'running' ? job.startedAt : undefined,\n completedAt: new Date().toISOString(),\n error: error instanceof Error ? error.message : String(error),\n };\n\n await this.jobQueue.updateJob(failedJob, job.status);\n }\n }\n\n /**\n * Update job progress (best-effort, doesn't throw)\n */\n protected async updateJobProgress(job: AnyJob): Promise<void> {\n try {\n await this.jobQueue.updateJob(job);\n } catch (error) {\n console.warn(`[${this.getWorkerName()}] Failed to update job progress:`, error);\n // Don't throw - progress updates are best-effort\n }\n }\n\n /**\n * Sleep utility\n */\n protected sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n /**\n * Emit completion event (optional hook for subclasses)\n * Override this to emit job-specific completion events (e.g., job.completed)\n */\n protected async emitCompletionEvent(_job: RunningJob<any, any>, _result: any): Promise<void> {\n // Default: do nothing\n // Subclasses can override to emit events\n }\n\n // Abstract methods to be implemented by subclasses\n\n /**\n * Get worker name (for logging)\n */\n protected abstract getWorkerName(): string;\n\n /**\n * Check if this worker can process the given job\n */\n protected abstract canProcessJob(job: AnyJob): boolean;\n\n /**\n * Execute the job (job-specific logic)\n * This is where the actual work happens\n * Return the result object (or void for jobs without results)\n * Throw an error to trigger retry logic\n */\n protected abstract executeJob(job: AnyJob): Promise<any>;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/job-queue.ts","../src/job-worker.ts"],"names":["fs","jobQueue"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Job Queue Manager\n *\n * Filesystem-based job queue with atomic operations.\n * Jobs are stored in directories by status for easy polling.\n */\n\nimport { promises as fs } from 'fs';\nimport * as path from 'path';\nimport type { AnyJob, JobStatus, JobQueryFilters, CancelledJob } from './types';\nimport type { JobId } from '@semiont/core';\n\nexport interface JobQueueConfig {\n dataDir: string;\n}\n\nexport class JobQueue {\n private jobsDir: string;\n\n constructor(config: JobQueueConfig) {\n this.jobsDir = path.join(config.dataDir, 'jobs');\n }\n\n /**\n * Initialize job queue directories\n */\n async initialize(): Promise<void> {\n const statuses: JobStatus[] = ['pending', 'running', 'complete', 'failed', 'cancelled'];\n\n for (const status of statuses) {\n const dir = path.join(this.jobsDir, status);\n await fs.mkdir(dir, { recursive: true });\n }\n\n console.log('[JobQueue] Initialized job directories');\n }\n\n /**\n * Create a new job\n */\n async createJob(job: AnyJob): Promise<void> {\n const jobPath = this.getJobPath(job.metadata.id, job.status);\n await fs.writeFile(jobPath, JSON.stringify(job, null, 2), 'utf-8');\n console.log(`[JobQueue] Created job ${job.metadata.id} with status ${job.status}`);\n }\n\n /**\n * Get a job by ID (searches all status directories)\n */\n async getJob(jobId: JobId): Promise<AnyJob | null> {\n const statuses: JobStatus[] = ['pending', 'running', 'complete', 'failed', 'cancelled'];\n\n for (const status of statuses) {\n const jobPath = this.getJobPath(jobId, status);\n try {\n const content = await fs.readFile(jobPath, 'utf-8');\n return JSON.parse(content) as AnyJob;\n } catch (error) {\n // File doesn't exist in this status directory, try next\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Update a job (atomic: delete old, write new)\n */\n async updateJob(job: AnyJob, oldStatus?: JobStatus): Promise<void> {\n // If oldStatus provided, delete from old location\n if (oldStatus && oldStatus !== job.status) {\n const oldPath = this.getJobPath(job.metadata.id, oldStatus);\n try {\n await fs.unlink(oldPath);\n } catch (error) {\n // Ignore if file doesn't exist\n }\n }\n\n // Write to new location\n const newPath = this.getJobPath(job.metadata.id, job.status);\n await fs.writeFile(newPath, JSON.stringify(job, null, 2), 'utf-8');\n\n if (oldStatus && oldStatus !== job.status) {\n console.log(`[JobQueue] Moved job ${job.metadata.id} from ${oldStatus} to ${job.status}`);\n } else {\n console.log(`[JobQueue] Updated job ${job.metadata.id} (status: ${job.status})`);\n }\n }\n\n /**\n * Poll for next pending job (FIFO)\n */\n async pollNextPendingJob(): Promise<AnyJob | null> {\n const pendingDir = path.join(this.jobsDir, 'pending');\n\n try {\n const files = await fs.readdir(pendingDir);\n\n if (files.length === 0) {\n return null;\n }\n\n // Sort by filename (job IDs have timestamps via nanoid)\n files.sort();\n\n const jobFile = files[0]!;\n const jobPath = path.join(pendingDir, jobFile);\n\n const content = await fs.readFile(jobPath, 'utf-8');\n return JSON.parse(content) as AnyJob;\n } catch (error) {\n console.error('[JobQueue] Error polling pending jobs:', error);\n return null;\n }\n }\n\n /**\n * List jobs with filters\n */\n async listJobs(filters: JobQueryFilters = {}): Promise<AnyJob[]> {\n const jobs: AnyJob[] = [];\n\n // Determine which status directories to scan\n const statuses: JobStatus[] = filters.status\n ? [filters.status]\n : ['pending', 'running', 'complete', 'failed', 'cancelled'];\n\n for (const status of statuses) {\n const statusDir = path.join(this.jobsDir, status);\n\n try {\n const files = await fs.readdir(statusDir);\n\n for (const file of files) {\n const jobPath = path.join(statusDir, file);\n const content = await fs.readFile(jobPath, 'utf-8');\n const job = JSON.parse(content) as AnyJob;\n\n // Apply filters\n if (filters.type && job.metadata.type !== filters.type) continue;\n if (filters.userId && job.metadata.userId !== filters.userId) continue;\n\n jobs.push(job);\n }\n } catch (error) {\n // Directory might not exist yet\n continue;\n }\n }\n\n // Sort by created descending (newest first)\n jobs.sort((a, b) => new Date(b.metadata.created).getTime() - new Date(a.metadata.created).getTime());\n\n // Apply pagination\n const offset = filters.offset || 0;\n const limit = filters.limit || 100;\n\n return jobs.slice(offset, offset + limit);\n }\n\n /**\n * Cancel a job\n */\n async cancelJob(jobId: JobId): Promise<boolean> {\n const job = await this.getJob(jobId);\n\n if (!job) {\n return false;\n }\n\n // Can only cancel pending or running jobs\n if (job.status !== 'pending' && job.status !== 'running') {\n return false;\n }\n\n const oldStatus = job.status;\n\n // Create cancelled job with proper structure\n const cancelledJob: CancelledJob<any> = {\n status: 'cancelled',\n metadata: job.metadata,\n params: job.status === 'pending' ? job.params : job.params,\n startedAt: job.status === 'running' ? job.startedAt : undefined,\n completedAt: new Date().toISOString(),\n };\n\n await this.updateJob(cancelledJob, oldStatus);\n return true;\n }\n\n /**\n * Clean up old completed/failed jobs (older than retention period)\n */\n async cleanupOldJobs(retentionHours: number = 24): Promise<number> {\n const cutoffTime = Date.now() - (retentionHours * 60 * 60 * 1000);\n let deletedCount = 0;\n\n const cleanupStatuses: JobStatus[] = ['complete', 'failed', 'cancelled'];\n\n for (const status of cleanupStatuses) {\n const statusDir = path.join(this.jobsDir, status);\n\n try {\n const files = await fs.readdir(statusDir);\n\n for (const file of files) {\n const jobPath = path.join(statusDir, file);\n const content = await fs.readFile(jobPath, 'utf-8');\n const job = JSON.parse(content) as AnyJob;\n\n if (job.status === 'complete' || job.status === 'failed' || job.status === 'cancelled') {\n const completedTime = new Date(job.completedAt).getTime();\n\n if (completedTime < cutoffTime) {\n await fs.unlink(jobPath);\n deletedCount++;\n }\n }\n }\n } catch (error) {\n console.error(`[JobQueue] Error cleaning up ${status} jobs:`, error);\n }\n }\n\n if (deletedCount > 0) {\n console.log(`[JobQueue] Cleaned up ${deletedCount} old jobs`);\n }\n\n return deletedCount;\n }\n\n /**\n * Get job file path\n */\n private getJobPath(jobId: JobId, status: JobStatus): string {\n return path.join(this.jobsDir, status, `${jobId}.json`);\n }\n\n /**\n * Get statistics about the queue\n */\n async getStats(): Promise<{\n pending: number;\n running: number;\n complete: number;\n failed: number;\n cancelled: number;\n }> {\n const stats = {\n pending: 0,\n running: 0,\n complete: 0,\n failed: 0,\n cancelled: 0\n };\n\n const statuses: JobStatus[] = ['pending', 'running', 'complete', 'failed', 'cancelled'];\n\n for (const status of statuses) {\n const statusDir = path.join(this.jobsDir, status);\n\n try {\n const files = await fs.readdir(statusDir);\n stats[status] = files.length;\n } catch (error) {\n // Directory might not exist yet\n stats[status] = 0;\n }\n }\n\n return stats;\n }\n}\n\n// Singleton instance\nlet jobQueue: JobQueue | null = null;\n\nexport function getJobQueue(): JobQueue {\n if (!jobQueue) {\n throw new Error('JobQueue not initialized. Call initializeJobQueue() first.');\n }\n return jobQueue;\n}\n\nexport async function initializeJobQueue(config: JobQueueConfig): Promise<JobQueue> {\n jobQueue = new JobQueue(config);\n await jobQueue.initialize();\n return jobQueue;\n}\n","/**\n * Job Worker Base Class\n *\n * Abstract worker that polls the job queue and processes jobs.\n * Subclasses implement specific job processing logic.\n */\n\nimport type { AnyJob, RunningJob, CompleteJob, FailedJob, PendingJob } from './types';\nimport type { JobQueue } from './job-queue';\n\nexport abstract class JobWorker {\n private running = false;\n private currentJob: AnyJob | null = null;\n private pollIntervalMs: number;\n private errorBackoffMs: number;\n protected jobQueue: JobQueue;\n\n constructor(\n jobQueue: JobQueue,\n pollIntervalMs: number = 1000,\n errorBackoffMs: number = 5000\n ) {\n this.jobQueue = jobQueue;\n this.pollIntervalMs = pollIntervalMs;\n this.errorBackoffMs = errorBackoffMs;\n }\n\n /**\n * Start the worker (polls queue in loop)\n */\n async start(): Promise<void> {\n this.running = true;\n console.log(`[${this.getWorkerName()}] Started`);\n\n while (this.running) {\n try {\n const job = await this.pollNextJob();\n\n if (job) {\n await this.processJob(job);\n } else {\n // No jobs available, wait before polling again\n await this.sleep(this.pollIntervalMs);\n }\n } catch (error) {\n console.error(`[${this.getWorkerName()}] Error in main loop:`, error);\n // Back off on error to avoid tight error loops\n await this.sleep(this.errorBackoffMs);\n }\n }\n\n console.log(`[${this.getWorkerName()}] Stopped`);\n }\n\n /**\n * Stop the worker (graceful shutdown)\n */\n async stop(): Promise<void> {\n console.log(`[${this.getWorkerName()}] Stopping...`);\n this.running = false;\n\n // Wait for current job to finish (with timeout)\n const timeout = 60000; // 60 seconds\n const startTime = Date.now();\n\n while (this.currentJob && (Date.now() - startTime) < timeout) {\n await this.sleep(100);\n }\n\n if (this.currentJob) {\n console.warn(`[${this.getWorkerName()}] Forced shutdown while processing job ${this.currentJob.metadata.id}`);\n }\n }\n\n /**\n * Poll for next job to process\n */\n private async pollNextJob(): Promise<AnyJob | null> {\n const job = await this.jobQueue.pollNextPendingJob();\n\n if (job && this.canProcessJob(job)) {\n return job;\n }\n\n return null;\n }\n\n /**\n * Process a job (handles state transitions and error handling)\n */\n private async processJob(job: AnyJob): Promise<void> {\n this.currentJob = job;\n\n try {\n // Only process pending jobs\n if (job.status !== 'pending') {\n console.warn(`[${this.getWorkerName()}] Skipping non-pending job ${job.metadata.id}`);\n return;\n }\n\n // Create running job\n const runningJob: RunningJob<any, any> = {\n status: 'running',\n metadata: job.metadata,\n params: job.params,\n startedAt: new Date().toISOString(),\n progress: {}, // Initialize with empty progress\n };\n\n await this.jobQueue.updateJob(runningJob, 'pending');\n\n console.log(`[${this.getWorkerName()}] 🔄 Processing job ${job.metadata.id} (type: ${job.metadata.type})`);\n\n // Execute job-specific logic (passing running job) and get result\n const result = await this.executeJob(runningJob);\n\n // Allow subclasses to emit completion events with result data\n await this.emitCompletionEvent(runningJob, result);\n\n // Move to complete state with result\n const completeJob: CompleteJob<any, any> = {\n status: 'complete',\n metadata: runningJob.metadata,\n params: runningJob.params,\n startedAt: runningJob.startedAt,\n completedAt: new Date().toISOString(),\n result: result ?? {}, // Use returned result or empty object\n };\n\n await this.jobQueue.updateJob(completeJob, 'running');\n\n console.log(`[${this.getWorkerName()}] ✅ Job ${job.metadata.id} completed successfully`);\n\n } catch (error) {\n await this.handleJobFailure(job, error);\n } finally {\n this.currentJob = null;\n }\n }\n\n /**\n * Handle job failure (retry or move to failed)\n */\n protected async handleJobFailure(job: AnyJob, error: any): Promise<void> {\n const updatedMetadata = {\n ...job.metadata,\n retryCount: job.metadata.retryCount + 1,\n };\n\n if (updatedMetadata.retryCount < updatedMetadata.maxRetries) {\n console.log(`[${this.getWorkerName()}] Job ${job.metadata.id} failed, will retry (${updatedMetadata.retryCount}/${updatedMetadata.maxRetries})`);\n console.log(`[${this.getWorkerName()}] Error:`, error);\n\n // Move back to pending for retry\n const retryJob: PendingJob<any> = {\n status: 'pending',\n metadata: updatedMetadata,\n params: job.status === 'pending' ? job.params : job.params,\n };\n\n await this.jobQueue.updateJob(retryJob, job.status);\n\n } else {\n console.error(`[${this.getWorkerName()}] ❌ Job ${job.metadata.id} failed permanently after ${updatedMetadata.retryCount} retries`);\n console.error(`[${this.getWorkerName()}] Error:`, error);\n\n // Move to failed state\n const failedJob: FailedJob<any> = {\n status: 'failed',\n metadata: updatedMetadata,\n params: job.status === 'pending' ? job.params : job.params,\n startedAt: job.status === 'running' ? job.startedAt : undefined,\n completedAt: new Date().toISOString(),\n error: error instanceof Error ? error.message : String(error),\n };\n\n await this.jobQueue.updateJob(failedJob, job.status);\n }\n }\n\n /**\n * Update job progress (best-effort, doesn't throw)\n */\n protected async updateJobProgress(job: AnyJob): Promise<void> {\n try {\n await this.jobQueue.updateJob(job);\n } catch (error) {\n console.warn(`[${this.getWorkerName()}] Failed to update job progress:`, error);\n // Don't throw - progress updates are best-effort\n }\n }\n\n /**\n * Sleep utility\n */\n protected sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n /**\n * Emit completion event (optional hook for subclasses)\n * Override this to emit job-specific completion events (e.g., job.completed)\n */\n protected async emitCompletionEvent(_job: RunningJob<any, any>, _result: any): Promise<void> {\n // Default: do nothing\n // Subclasses can override to emit events\n }\n\n // Abstract methods to be implemented by subclasses\n\n /**\n * Get worker name (for logging)\n */\n protected abstract getWorkerName(): string;\n\n /**\n * Check if this worker can process the given job\n */\n protected abstract canProcessJob(job: AnyJob): boolean;\n\n /**\n * Execute the job (job-specific logic)\n * This is where the actual work happens\n * Return the result object (or void for jobs without results)\n * Throw an error to trigger retry logic\n */\n protected abstract executeJob(job: AnyJob): Promise<any>;\n}\n"]}
|