-
Notifications
You must be signed in to change notification settings - Fork 0
chore(slack-bot): Add mockup logic for long-read short-write commands #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # | ||
| # Quadrant-based workers: | ||
| # sr - Short-Read unified worker (handles /echo, /status, etc.) | ||
| # sr - Short-Read unified worker (handles /echo, /status-check, etc.) |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment incorrectly lists /status-check as an example command. Based on the command registry (src/shared/command-registry.ts) and SR worker implementation (src/workers/sr/index.ts), the actual command is /status, not /status-check.
| /** | ||
| * Log worker performance metrics for monitoring and analysis | ||
| */ | ||
| function logWorkerMetrics(params: { | ||
| correlationId?: string; | ||
| command?: string; | ||
| totalE2eMs?: number; | ||
| workerDurationMs: number; | ||
| queueWaitMs?: number; | ||
| syncResponseMs?: number; | ||
| asyncResponseMs?: number; | ||
| success: boolean; | ||
| errorType?: string; | ||
| errorMessage?: string; | ||
| }) { | ||
| logger.info('Performance metrics', { | ||
| ...params, | ||
| component: 'sw-worker', // Add component identifier for filtering | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Handler result with performance metrics | ||
| */ | ||
| interface HandlerResult { | ||
| syncResponseMs?: number; | ||
| asyncResponseMs?: number; | ||
| } | ||
|
|
||
| /** | ||
| * Command handler registry | ||
| * Maps command names to their handler functions | ||
| */ | ||
| const COMMAND_HANDLERS: Record< | ||
| string, | ||
| (message: WorkerMessage, messageId: string) => Promise<HandlerResult> | ||
| > = { | ||
| // Add new short-write commands here (no infrastructure changes needed!) | ||
| // '/scale': handleScale, | ||
| // '/restart': handleRestart, | ||
| }; | ||
|
|
||
| /** | ||
| * Unified SW worker handler | ||
| * Routes commands to appropriate handlers based on command type | ||
| */ | ||
| export async function handler(event: SQSEvent): Promise<SQSBatchResponse> { | ||
| logger.info('SW unified worker invoked', { | ||
| recordCount: event.Records.length, | ||
| quadrant: 'short-write', | ||
| }); | ||
|
|
||
| const batchItemFailures: { itemIdentifier: string }[] = []; | ||
|
|
||
| for (const record of event.Records) { | ||
| const startTime = Date.now(); | ||
| let messageLogger = logger; | ||
| let correlationId: string | undefined; | ||
|
|
||
| try { | ||
| const message: WorkerMessage = JSON.parse(record.body); | ||
| correlationId = message.correlation_id; | ||
|
|
||
| // Create child logger with correlation ID for request tracing | ||
| messageLogger = logger.child(correlationId || record.messageId, { | ||
| component: 'sw-worker', | ||
| command: message.command, | ||
| userId: message.user_id, | ||
| quadrant: 'short-write', | ||
| }); | ||
|
|
||
| messageLogger.info('Routing command to handler', { | ||
| command: message.command, | ||
| text: message.text, | ||
| user: message.user_name, | ||
| messageId: record.messageId, | ||
| }); | ||
|
|
||
| // Find handler for command | ||
| const handler = COMMAND_HANDLERS[message.command]; | ||
|
|
||
| if (!handler) { | ||
| const availableCommands = Object.keys(COMMAND_HANDLERS).join(', '); | ||
| const errorMsg = `Unknown command: ${message.command}. Available short-write commands: ${availableCommands || 'none'}`; | ||
|
|
||
| messageLogger.error(errorMsg, new Error('Unknown command'), { | ||
| command: message.command, | ||
| availableCommands, | ||
| }); | ||
|
|
||
| throw new Error(errorMsg); | ||
| } | ||
|
|
||
| // Execute handler and get performance metrics | ||
| const handlerResult = await handler(message, record.messageId); | ||
|
|
||
| const totalDuration = Date.now() - startTime; | ||
| const e2eDuration = message.api_gateway_start_time | ||
| ? Date.now() - message.api_gateway_start_time | ||
| : undefined; | ||
|
|
||
| // Log structured performance metrics for CloudWatch Insights analysis | ||
| logWorkerMetrics({ | ||
| correlationId, | ||
| command: message.command, | ||
| totalE2eMs: e2eDuration, | ||
| workerDurationMs: totalDuration, | ||
| queueWaitMs: e2eDuration ? Math.max(0, e2eDuration - totalDuration) : undefined, | ||
| syncResponseMs: handlerResult.syncResponseMs, | ||
| asyncResponseMs: handlerResult.asyncResponseMs, | ||
| success: true, | ||
| }); | ||
|
|
||
| messageLogger.info('Command processed successfully', { | ||
| command: message.command, | ||
| duration: totalDuration, | ||
| e2eDuration, | ||
| }); | ||
|
|
||
| } catch (error) { | ||
| const duration = Date.now() - startTime; | ||
| const err = error as Error; | ||
|
|
||
| messageLogger.error('Failed to process command', err, { | ||
| messageId: record.messageId, | ||
| duration, | ||
| }); | ||
|
|
||
| // Log performance metrics even for failures | ||
| logWorkerMetrics({ | ||
| correlationId, | ||
| workerDurationMs: duration, | ||
| success: false, | ||
| errorType: err.name, | ||
| errorMessage: err.message, | ||
| }); | ||
|
|
||
| // Add to failed items for retry | ||
| batchItemFailures.push({ itemIdentifier: record.messageId }); | ||
| } | ||
| } | ||
|
|
||
| logger.info('SW worker batch complete', { | ||
| total: event.Records.length, | ||
| failed: batchItemFailures.length, | ||
| succeeded: event.Records.length - batchItemFailures.length, | ||
| }); | ||
|
|
||
| return { batchItemFailures }; | ||
| } |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The worker implementation contains significant code duplication with the SR worker implementation (lines 11-160 are nearly identical between SW, LR, and SR workers, with only component names differing). Consider extracting the common worker logic into a shared utility function that accepts configuration (component name, quadrant name) to improve maintainability. This would ensure that future changes to error handling, metrics logging, or batch processing logic only need to be made in one place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to apply changes based on this feedback
| /** | ||
| * Log worker performance metrics for monitoring and analysis | ||
| */ | ||
| function logWorkerMetrics(params: { | ||
| correlationId?: string; | ||
| command?: string; | ||
| totalE2eMs?: number; | ||
| workerDurationMs: number; | ||
| queueWaitMs?: number; | ||
| syncResponseMs?: number; | ||
| asyncResponseMs?: number; | ||
| success: boolean; | ||
| errorType?: string; | ||
| errorMessage?: string; | ||
| }) { | ||
| logger.info('Performance metrics', { | ||
| ...params, | ||
| component: 'lr-worker', // Add component identifier for filtering | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Handler result with performance metrics | ||
| */ | ||
| interface HandlerResult { | ||
| syncResponseMs?: number; | ||
| asyncResponseMs?: number; | ||
| } | ||
|
|
||
| /** | ||
| * Command handler registry | ||
| * Maps command names to their handler functions | ||
| */ | ||
| const COMMAND_HANDLERS: Record< | ||
| string, | ||
| (message: WorkerMessage, messageId: string) => Promise<HandlerResult> | ||
| > = { | ||
| // Add new long-read commands here (no infrastructure changes needed!) | ||
| // '/analyze': handleAnalyze, | ||
| // '/report': handleReport, | ||
| }; | ||
|
|
||
| /** | ||
| * Unified LR worker handler | ||
| * Routes commands to appropriate handlers based on command type | ||
| */ | ||
| export async function handler(event: SQSEvent): Promise<SQSBatchResponse> { | ||
| logger.info('LR unified worker invoked', { | ||
| recordCount: event.Records.length, | ||
| quadrant: 'long-read', | ||
| }); | ||
|
|
||
| const batchItemFailures: { itemIdentifier: string }[] = []; | ||
|
|
||
| for (const record of event.Records) { | ||
| const startTime = Date.now(); | ||
| let messageLogger = logger; | ||
| let correlationId: string | undefined; | ||
|
|
||
| try { | ||
| const message: WorkerMessage = JSON.parse(record.body); | ||
| correlationId = message.correlation_id; | ||
|
|
||
| // Create child logger with correlation ID for request tracing | ||
| messageLogger = logger.child(correlationId || record.messageId, { | ||
| component: 'lr-worker', | ||
| command: message.command, | ||
| userId: message.user_id, | ||
| quadrant: 'long-read', | ||
| }); | ||
|
|
||
| messageLogger.info('Routing command to handler', { | ||
| command: message.command, | ||
| text: message.text, | ||
| user: message.user_name, | ||
| messageId: record.messageId, | ||
| }); | ||
|
|
||
| // Find handler for command | ||
| const handler = COMMAND_HANDLERS[message.command]; | ||
|
|
||
| if (!handler) { | ||
| const availableCommands = Object.keys(COMMAND_HANDLERS).join(', '); | ||
| const errorMsg = `Unknown command: ${message.command}. Available long-read commands: ${availableCommands || 'none'}`; | ||
|
|
||
| messageLogger.error(errorMsg, new Error('Unknown command'), { | ||
| command: message.command, | ||
| availableCommands, | ||
| }); | ||
|
|
||
| throw new Error(errorMsg); | ||
| } | ||
|
|
||
| // Execute handler and get performance metrics | ||
| const handlerResult = await handler(message, record.messageId); | ||
|
|
||
| const totalDuration = Date.now() - startTime; | ||
| const e2eDuration = message.api_gateway_start_time | ||
| ? Date.now() - message.api_gateway_start_time | ||
| : undefined; | ||
|
|
||
| // Log structured performance metrics for CloudWatch Insights analysis | ||
| logWorkerMetrics({ | ||
| correlationId, | ||
| command: message.command, | ||
| totalE2eMs: e2eDuration, | ||
| workerDurationMs: totalDuration, | ||
| queueWaitMs: e2eDuration ? Math.max(0, e2eDuration - totalDuration) : undefined, | ||
| syncResponseMs: handlerResult.syncResponseMs, | ||
| asyncResponseMs: handlerResult.asyncResponseMs, | ||
| success: true, | ||
| }); | ||
|
|
||
| messageLogger.info('Command processed successfully', { | ||
| command: message.command, | ||
| duration: totalDuration, | ||
| e2eDuration, | ||
| }); | ||
|
|
||
| } catch (error) { | ||
| const duration = Date.now() - startTime; | ||
| const err = error as Error; | ||
|
|
||
| messageLogger.error('Failed to process command', err, { | ||
| messageId: record.messageId, | ||
| duration, | ||
| }); | ||
|
|
||
| // Log performance metrics even for failures | ||
| logWorkerMetrics({ | ||
| correlationId, | ||
| workerDurationMs: duration, | ||
| success: false, | ||
| errorType: err.name, | ||
| errorMessage: err.message, | ||
| }); | ||
|
|
||
| // Add to failed items for retry | ||
| batchItemFailures.push({ itemIdentifier: record.messageId }); | ||
| } | ||
| } | ||
|
|
||
| logger.info('LR worker batch complete', { | ||
| total: event.Records.length, | ||
| failed: batchItemFailures.length, | ||
| succeeded: event.Records.length - batchItemFailures.length, | ||
| }); | ||
|
|
||
| return { batchItemFailures }; | ||
| } |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The worker implementation contains significant code duplication with the SR worker implementation (lines 11-160 are nearly identical between LR, SW, and SR workers, with only component names differing). Consider extracting the common worker logic into a shared utility function that accepts configuration (component name, quadrant name) to improve maintainability. This would ensure that future changes to error handling, metrics logging, or batch processing logic only need to be made in one place.
No description provided.