Skip to content

Commit 052bbc5

Browse files
committed
feat: add performance metrics logging to SR worker
Restore structured performance metrics logging that was present in the original echo worker, enabling E2E latency tracking and component breakdown analysis in CloudWatch. Implementation matches the original echo/index.ts pattern from PR #18: - SR worker collects timing metrics and logs 'Performance metrics' - Handler returns syncResponseMs and asyncResponseMs - Worker calculates E2E, queue wait, and total duration - Metrics logged for both success and failure cases Performance metrics fields: - totalE2eMs: API Gateway → final response (end-to-end) - workerDurationMs: Lambda execution time - queueWaitMs: Time message spent in SQS (calculated) - syncResponseMs: Sync Slack response time (from handler) - asyncResponseMs: Async Slack response time (from handler) - component: 'sr-worker' for CloudWatch filtering - correlationId, command, success, errorType, errorMessage Changes: - Removed artificial 2-second sleep delay from echo handler - Echo handler now returns HandlerResult with timing metrics - SR worker logs structured metrics via logWorkerMetrics() This restores server-side metrics collection after the quadrant-based refactor, enabling performance test analysis scripts to work correctly.
1 parent 22273a9 commit 052bbc5

2 files changed

Lines changed: 95 additions & 20 deletions

File tree

applications/chatops/slack-bot/src/workers/handlers/echo.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,28 @@ import { logger } from '../../shared/logger';
55
import { sendSlackResponse } from '../../shared/slack-client';
66
import { WorkerMessage } from '../../shared/types';
77

8+
/**
9+
* Handler result with performance metrics
10+
*/
11+
interface HandlerResult {
12+
syncResponseMs?: number;
13+
asyncResponseMs?: number;
14+
}
15+
816
/**
917
* Handle echo command
1018
* Sends synchronous and asynchronous responses to Slack
19+
*
20+
* @param message - Worker message from SQS
21+
* @param messageId - SQS message ID
22+
* @returns Performance metrics for the worker to log
1123
*/
12-
export async function handleEcho(message: WorkerMessage, messageId: string): Promise<void> {
13-
const startTime = Date.now();
24+
export async function handleEcho(
25+
message: WorkerMessage,
26+
messageId: string
27+
): Promise<HandlerResult> {
28+
let syncResponseMs: number | undefined;
29+
let asyncResponseMs: number | undefined;
1430

1531
// Create child logger with correlation ID for request tracing
1632
const messageLogger = logger.child(message.correlation_id || messageId, {
@@ -44,15 +60,12 @@ export async function handleEcho(message: WorkerMessage, messageId: string): Pro
4460
response_type: 'in_channel',
4561
text: `sync ${message.text}`,
4662
});
47-
const syncDuration = Date.now() - syncStart;
63+
syncResponseMs = Date.now() - syncStart;
4864

4965
messageLogger.info('Sync response sent', {
50-
duration: syncDuration,
66+
duration: syncResponseMs,
5167
});
5268

53-
// Simulate some async work
54-
await new Promise((resolve) => setTimeout(resolve, 2000));
55-
5669
// Send asynchronous response
5770
const asyncStart = Date.now();
5871
await sendSlackResponse(message.response_url, {
@@ -77,19 +90,21 @@ export async function handleEcho(message: WorkerMessage, messageId: string): Pro
7790
},
7891
],
7992
});
80-
const asyncDuration = Date.now() - asyncStart;
93+
asyncResponseMs = Date.now() - asyncStart;
8194

8295
messageLogger.info('Async response sent', {
83-
duration: asyncDuration,
96+
duration: asyncResponseMs,
8497
});
8598

8699
subsegment?.close();
87100

88-
const totalDuration = Date.now() - startTime;
101+
messageLogger.info('Echo command processed successfully');
89102

90-
messageLogger.info('Echo command processed successfully', {
91-
totalDuration,
92-
});
103+
// Return performance metrics for the worker to log
104+
return {
105+
syncResponseMs,
106+
asyncResponseMs,
107+
};
93108
} catch (error) {
94109
subsegment?.addError(error as Error);
95110
subsegment?.close();

applications/chatops/slack-bot/src/workers/sr/index.ts

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,43 @@ import { handleEcho } from '../handlers/echo';
99
// import { handleStatus } from '../handlers/status';
1010
// import { handleHelp } from '../handlers/help';
1111

12+
/**
13+
* Log worker performance metrics for monitoring and analysis
14+
*/
15+
function logWorkerMetrics(params: {
16+
correlationId?: string;
17+
command?: string;
18+
totalE2eMs?: number;
19+
workerDurationMs: number;
20+
queueWaitMs?: number;
21+
syncResponseMs?: number;
22+
asyncResponseMs?: number;
23+
success: boolean;
24+
errorType?: string;
25+
errorMessage?: string;
26+
}) {
27+
logger.info('Performance metrics', {
28+
...params,
29+
component: 'sr-worker', // Add component identifier for filtering
30+
});
31+
}
32+
33+
/**
34+
* Handler result with performance metrics
35+
*/
36+
interface HandlerResult {
37+
syncResponseMs?: number;
38+
asyncResponseMs?: number;
39+
}
40+
1241
/**
1342
* Command handler registry
1443
* Maps command names to their handler functions
1544
*/
16-
const COMMAND_HANDLERS: Record<string, (message: WorkerMessage, messageId: string) => Promise<void>> = {
45+
const COMMAND_HANDLERS: Record<
46+
string,
47+
(message: WorkerMessage, messageId: string) => Promise<HandlerResult>
48+
> = {
1749
'/echo': handleEcho,
1850
// Add new short-read commands here (no infrastructure changes needed!)
1951
// '/status': handleStatus,
@@ -35,10 +67,11 @@ export async function handler(event: SQSEvent): Promise<SQSBatchResponse> {
3567
for (const record of event.Records) {
3668
const startTime = Date.now();
3769
let messageLogger = logger;
70+
let correlationId: string | undefined;
3871

3972
try {
4073
const message: WorkerMessage = JSON.parse(record.body);
41-
const correlationId = message.correlation_id;
74+
correlationId = message.correlation_id;
4275

4376
// Create child logger with correlation ID for request tracing
4477
messageLogger = logger.child(correlationId || record.messageId, {
@@ -70,23 +103,50 @@ export async function handler(event: SQSEvent): Promise<SQSBatchResponse> {
70103
throw new Error(errorMsg);
71104
}
72105

73-
// Execute handler
74-
await handler(message, record.messageId);
106+
// Execute handler and get performance metrics
107+
const handlerResult = await handler(message, record.messageId);
108+
109+
const totalDuration = Date.now() - startTime;
110+
const e2eDuration = message.api_gateway_start_time
111+
? Date.now() - message.api_gateway_start_time
112+
: undefined;
113+
114+
// Log structured performance metrics for CloudWatch Insights analysis
115+
logWorkerMetrics({
116+
correlationId,
117+
command: message.command,
118+
totalE2eMs: e2eDuration,
119+
workerDurationMs: totalDuration,
120+
queueWaitMs: e2eDuration ? Math.max(0, e2eDuration - totalDuration) : undefined,
121+
syncResponseMs: handlerResult.syncResponseMs,
122+
asyncResponseMs: handlerResult.asyncResponseMs,
123+
success: true,
124+
});
75125

76-
const duration = Date.now() - startTime;
77126
messageLogger.info('Command processed successfully', {
78127
command: message.command,
79-
duration,
128+
duration: totalDuration,
129+
e2eDuration,
80130
});
81131

82132
} catch (error) {
83133
const duration = Date.now() - startTime;
134+
const err = error as Error;
84135

85-
messageLogger.error('Failed to process command', error as Error, {
136+
messageLogger.error('Failed to process command', err, {
86137
messageId: record.messageId,
87138
duration,
88139
});
89140

141+
// Log performance metrics even for failures
142+
logWorkerMetrics({
143+
correlationId,
144+
workerDurationMs: duration,
145+
success: false,
146+
errorType: err.name,
147+
errorMessage: err.message,
148+
});
149+
90150
// Add to failed items for retry
91151
batchItemFailures.push({ itemIdentifier: record.messageId });
92152
}

0 commit comments

Comments
 (0)