npm package: @qrvey/process-controller
Description: General Process Controller for managing and monitoring job lifecycle with statistics
Author: Qrvey
Latest version: 1.0.0-661

# @qrvey/process-controller

General Process Controller for managing and monitoring job lifecycle with detailed statistics tracking.

## Features

- **Singleton Pattern**: Ensures only one instance manages all processes
- **Job Lifecycle Management**: Register and deregister jobs with automatic tracking
- **Statistics Tracking**: Automatic calculation of job execution times, averages, and more
- **Graceful Shutdown**: Handles shutdown requests while waiting for running jobs to complete
- **Instance States**: ACTIVE, SHUTDOWN_IN_PROGRESS, and INACTIVE states
- **Configurable Logging**: Custom logger support with enable/disable option
- **Event Callbacks**: Hooks for job registration, deregistration, and status changes
- **Utility Methods**: Check job existence, count jobs, get individual jobs, and more
- **TypeScript Support**: Full TypeScript type definitions included
- **Modular Architecture**: Well-organized code structure with separate modules

## Installation

\`\`\`bash
npm install @qrvey/process-controller
# or
yarn add @qrvey/process-controller
\`\`\`

## Usage

### Basic Example

\`\`\`typescript
import { GeneralProcessController, INSTANCE_STATUS, WORKER_STATUS } from '@qrvey/process-controller';

// Initialize the controller (do this once at application startup)
const controller = GeneralProcessController.initialize();

// Get the controller instance anywhere in your code
const gpc = GeneralProcessController.getInstance();

// Register a job
gpc.register('job-123', { 
    userId: '456', 
    operation: 'data-processing' 
});

// Do your work...
await processData();

// Deregister the job when complete
gpc.deregister('job-123');

// Get current statistics
const stats = gpc.getFormattedStatistics();
console.log(stats);
// Output:
// {
//   totalJobsInProgress: 0,
//   totalJobsCount: 1,
//   totalJobsTime: "2.45 s",
//   averageJobTime: "2.45 s",
//   maxJobTime: "2.45 s",
//   minJobTime: "2.45 s",
//   startTime: "2025-12-16T10:30:00.000Z",
//   endTime: "2025-12-16T10:30:02.450Z"
// }
\`\`\`

### Advanced Configuration

\`\`\`typescript
import { GeneralProcessController } from '@qrvey/process-controller';

// Initialize with custom configuration
const controller = GeneralProcessController.initialize({
    // Disable console logging
    enableLogging: false,
    
    // Or provide custom logger
    logger: {
        log: (msg) => myLogger.info(msg),
        warn: (msg) => myLogger.warn(msg),
        error: (msg) => myLogger.error(msg),
    },
    
    // Callbacks for events
    onJobRegister: (pid, payload) => {
        console.log(\`Job \${pid} started with\`, payload);
    },
    
    onJobDeregister: (pid, duration) => {
        console.log(\`Job \${pid} completed in \${duration}ms\`);
    },
    
    onStatusChange: (oldStatus, newStatus) => {
        console.log(\`Status changed: \${oldStatus} -> \${newStatus}\`);
    },
});
\`\`\`

### Graceful Shutdown

\`\`\`typescript
import { GeneralProcessController, INSTANCE_STATUS } from '@qrvey/process-controller';

const gpcInstance = GeneralProcessController.getInstance();

// Handle shutdown signals
['SIGTERM', 'SIGINT'].forEach(signal => {
    process.on(signal, async () => {
        console.log(\`\${signal} signal received.\`);
        
        // Trigger GPC shutdown
        gpcInstance.shutdown(\`\${signal}_SIGNAL\`);
        
        // Wait until all the processes are finished
        while (gpcInstance.getStatus() !== INSTANCE_STATUS.INACTIVE) {
            await new Promise(resolve => setTimeout(resolve, 1000));
        }
        
        console.log(\`\${signal} signal processed.\`);
        process.exit(0);
    });
});
\`\`\`

### Use in Lambda Functions

\`\`\`typescript
import { GeneralProcessController } from '@qrvey/process-controller';

// Initialize once (cold start)
const controller = GeneralProcessController.initialize({
    enableLogging: process.env.ENABLE_LOGGING === 'true',
});

export const handler = async (event: any) => {
    const jobId = event.jobId;
    
    try {
        // Register the job
        controller.register(jobId, { event });
        
        // Process the event
        const result = await processEvent(event);
        
        return {
            statusCode: 200,
            body: JSON.stringify(result)
        };
    } finally {
        // Always deregister
        controller.deregister(jobId);
    }
};
\`\`\`

### Utility Methods

\`\`\`typescript
const controller = GeneralProcessController.getInstance();

// Check instance status
if (controller.isActive()) {
    // Safe to register jobs
}

// Get job count
const activeJobs = controller.getJobCount();

// Check if specific job exists
if (controller.hasJob('job-123')) {
    console.log('Job is still running');
}

// Get job details
const job = controller.getJob('job-123');
if (job) {
    console.log('Job payload:', job.payload);
    console.log('Started at:', job.ts);
}

// Get raw statistics (in milliseconds)
const rawStats = controller.getStatistics();

// Reset statistics (keeps running jobs)
controller.resetStatistics();

// Get complete process list
const list = controller.getList();
console.log(list);
// {
//   instanceId: "xyz123",
//   instanceStatus: "ACTIVE",
//   workerStatus: "BUSY",
//   workerDetails: [...],
//   statistics: {...}
// }
\`\`\`

## API Reference

### Static Methods

#### \`static initialize(config?: ProcessControllerConfig): GeneralProcessController\`
Initializes and returns the singleton instance. Safe to call multiple times.

#### \`static getInstance(): GeneralProcessController\`
Gets the singleton instance. Throws error if not initialized.

#### \`static resetInstance(): void\`
Resets the singleton instance (useful for testing).

### Instance Management

#### \`getInstanceId(): string\`
Returns the unique instance identifier.

#### \`getStatus(): INSTANCE_STATUS\`
Returns the current instance status (ACTIVE, SHUTDOWN_IN_PROGRESS, or INACTIVE).

#### \`start(): void\`
Starts the controller (called automatically on initialization).

#### \`shutdown(source?: string): void\`
Initiates graceful shutdown. Rejects new jobs and waits for current jobs to complete.

### Status Checks

#### \`isActive(): boolean\`
Returns true if the instance is active and accepting jobs.

#### \`isShuttingDown(): boolean\`
Returns true if the instance is shutting down.

#### \`isInactive(): boolean\`
Returns true if the instance is inactive.

### Job Management

#### \`register(pid: string, payload?: Record<string, any>): void\`
Registers a new job with the given process ID and optional payload. Throws error if PID already exists or if controller is not active.

#### \`deregister(pid: string): void\`
Deregisters a job and updates statistics.

#### \`hasJob(pid: string): boolean\`
Returns true if a job with the given PID exists.

#### \`getJob(pid: string): JobItem | undefined\`
Returns the job item for the given PID, or undefined if not found.

#### \`getJobCount(): number\`
Returns the number of currently running jobs.

### Statistics

#### \`getStatistics(): Statistics\`
Returns raw statistics with time values in milliseconds.

#### \`getFormattedStatistics(): FormattedStatistics\`
Returns formatted statistics with human-readable time values.

#### \`resetStatistics(): void\`
Resets all statistics (does not affect running jobs).

#### \`getList(): ProcessList\`
Returns complete information about instance status, workers, and statistics.

## Types

\`\`\`typescript
enum INSTANCE_STATUS {
    ACTIVE = 'ACTIVE',
    SHUTDOWN_IN_PROGRESS = 'SHUTDOWN_IN_PROGRESS',
    INACTIVE = 'INACTIVE',
}

enum WORKER_STATUS {
    IDLE = 'IDLE',
    BUSY = 'BUSY',
}

interface JobItem {
    pid: string;
    ts: string;
    payload: Record<string, any>;
}

interface Statistics {
    totalJobsCount: number;
    totalJobsTime: number;        // in milliseconds
    averageJobTime: number;       // in milliseconds
    maxJobTime: number;           // in milliseconds
    minJobTime: number;           // in milliseconds
    startTime: number | null;     // timestamp
    endTime: number | null;       // timestamp
}

interface FormattedStatistics {
    totalJobsInProgress: number;
    totalJobsCount: number;
    totalJobsTime: string;        // formatted as "X.XX s"
    averageJobTime: string;
    maxJobTime: string;
    minJobTime: string;
    startTime: string | null;     // ISO string
    endTime: string | null;       // ISO string
}

interface ProcessList {
    instanceId: string;
    instanceStatus: string;
    workerStatus: string;
    workerDetails: JobItem[];
    statistics: FormattedStatistics;
}

interface ProcessControllerConfig {
    logger?: {
        log?: (...args: any[]) => void;
        warn?: (...args: any[]) => void;
        error?: (...args: any[]) => void;
    };
    enableLogging?: boolean;
    onJobRegister?: (pid: string, payload: Record<string, any>) => void;
    onJobDeregister?: (pid: string, duration: number) => void;
    onStatusChange?: (oldStatus: string, newStatus: string) => void;
}
\`\`\`

## Project Structure

\`\`\`
src/
├── constants/           # Enums and constants
│   └── index.ts
├── types/              # TypeScript interfaces and types
│   └── index.ts
├── utils/              # Utility functions
│   ├── logger.ts
│   ├── formatters.ts
│   └── index.ts
├── GeneralProcessController.ts  # Main controller class
└── index.ts            # Public API exports
\`\`\`

## License

MIT

## Keywords

- qrvey
- process-controller
- job-manager
- graceful-shutdown
- statistics
- singleton
- worker-management
- lifecycle-management