give more time to push metrics before exiting
This commit is contained in:
parent
3b763ae5e7
commit
4817ed93d2
@ -24,6 +24,7 @@ export enum CommonMetrics {
|
|||||||
HTTP_CLIENT_ERROR = "HttpClientError",
|
HTTP_CLIENT_ERROR = "HttpClientError",
|
||||||
LOKI_ERROR = "LokiError",
|
LOKI_ERROR = "LokiError",
|
||||||
LOKI_LOG_AFTER_CLOSE = "LokiLogAfterClose",
|
LOKI_LOG_AFTER_CLOSE = "LokiLogAfterClose",
|
||||||
|
TWILIO_ISOLATION_BUSTED = "TwilioIsolationBusted",
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getMetricFromRegistry<T>(metricsRegistry: Registry, metric: string): T {
|
export function getMetricFromRegistry<T>(metricsRegistry: Registry, metric: string): T {
|
||||||
@ -33,7 +34,6 @@ export function getMetricFromRegistry<T>(metricsRegistry: Registry, metric: stri
|
|||||||
export function gracefullyEndLogger(logger: Logger): Promise<void> {
|
export function gracefullyEndLogger(logger: Logger): Promise<void> {
|
||||||
return new Promise((fulfill, reject) => {
|
return new Promise((fulfill, reject) => {
|
||||||
// Add logic for other transports here ...
|
// Add logic for other transports here ...
|
||||||
|
|
||||||
logger.on('finish', () => {
|
logger.on('finish', () => {
|
||||||
fulfill();
|
fulfill();
|
||||||
});
|
});
|
||||||
@ -42,6 +42,9 @@ export function gracefullyEndLogger(logger: Logger): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MINIMUM_MS_TO_SEND_RESPONSE: number = 250;
|
||||||
|
const FUNCTION_MAXIMUM_DURATION_MS: number = 10_000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A decorator for twilio handlers. It provides a metrics registry and
|
* A decorator for twilio handlers. It provides a metrics registry and
|
||||||
* should implement timeout and cleanup jobs based on lambda timeout
|
* should implement timeout and cleanup jobs based on lambda timeout
|
||||||
@ -92,6 +95,11 @@ export function withMetrics<T extends DoormanLambdaContext, U extends BaseEvent>
|
|||||||
help: "Tried to write logs after log stream closed",
|
help: "Tried to write logs after log stream closed",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
metricsRegistry.registerMetric(new Counter({
|
||||||
|
name: CommonMetrics.TWILIO_ISOLATION_BUSTED,
|
||||||
|
help: "Twilio invocation lasted longer than 10s",
|
||||||
|
}));
|
||||||
|
|
||||||
// Create a Winston logger
|
// Create a Winston logger
|
||||||
const logger = createLogger({
|
const logger = createLogger({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
@ -199,13 +207,25 @@ export function withMetrics<T extends DoormanLambdaContext, U extends BaseEvent>
|
|||||||
console.timeEnd("[CommonHandler] nested handler time");
|
console.timeEnd("[CommonHandler] nested handler time");
|
||||||
|
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
const remainingTime = 10000 - (endTime - startTime);
|
const remainingTime = FUNCTION_MAXIMUM_DURATION_MS - (endTime - startTime);
|
||||||
|
|
||||||
|
if (remainingTime < 0) {
|
||||||
|
console.error("[CommonHandler] remaining time is negative for some reason...");
|
||||||
|
getMetricFromRegistry<Counter>(metricsRegistry, CommonMetrics.TWILIO_ISOLATION_BUSTED).inc(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// abandoning metrics, since there isn't enough time
|
||||||
|
if (remainingTime <= MINIMUM_MS_TO_SEND_RESPONSE) {
|
||||||
|
console.error("[CommonHandler] there is no time to send metrics / logs abandoning them");
|
||||||
|
callback(...result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`[CommonHandler] there is ${remainingTime} ms left to send metrics`);
|
console.log(`[CommonHandler] there is ${remainingTime} ms left to send metrics`);
|
||||||
|
|
||||||
let metricsTimeout = setTimeout(() => {
|
let metricsTimeout = setTimeout(() => {
|
||||||
callback(...result);
|
callback(...result);
|
||||||
}, remainingTime - 250);
|
}, remainingTime - MINIMUM_MS_TO_SEND_RESPONSE);
|
||||||
|
|
||||||
summaryTimer();
|
summaryTimer();
|
||||||
console.log("[CommonHandler] attempting to push metrics...");
|
console.log("[CommonHandler] attempting to push metrics...");
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
|||||||
let invokeId = `[${randomUUID()}]`;
|
let invokeId = `[${randomUUID()}]`;
|
||||||
let configString = event.config;
|
let configString = event.config;
|
||||||
let config: InfoResponseClient | undefined;
|
let config: InfoResponseClient | undefined;
|
||||||
console.log(invokeId, "starting execution");
|
console.log(invokeId + " starting execution");
|
||||||
|
|
||||||
// get by api or parse it out from query
|
// get by api or parse it out from query
|
||||||
if (!configString) {
|
if (!configString) {
|
||||||
@ -82,7 +82,7 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
|||||||
if (!discordLock) {
|
if (!discordLock) {
|
||||||
discordLock = true;
|
discordLock = true;
|
||||||
console.log(
|
console.log(
|
||||||
invokeId, "UnlockPromise: I was the fastest, so I will attempt to notify discord users before resolving with unlock"
|
invokeId + " UnlockPromise: I was the fastest, so I will attempt to notify discord users before resolving with unlock"
|
||||||
);
|
);
|
||||||
getMetricFromRegistry<Counter>(metricsRegistry, BuzzerActivatedMetrics.API_UNLOCK)
|
getMetricFromRegistry<Counter>(metricsRegistry, BuzzerActivatedMetrics.API_UNLOCK)
|
||||||
.inc({ door: config.door }, 1);
|
.inc({ door: config.door }, 1);
|
||||||
@ -91,11 +91,11 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
|||||||
resolve(twiml);
|
resolve(twiml);
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
invokeId, "UnlockPromise: dropping out of the race, graceful fallback is already notifiying discord users"
|
invokeId + " UnlockPromise: dropping out of the race, graceful fallback is already notifiying discord users"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).catch(err => console.log(invokeId, err));
|
}).catch(err => console.log(invokeId + err));
|
||||||
}, 1250));
|
}, 1250));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
|||||||
.inc({ door: config.door }, 1);
|
.inc({ door: config.door }, 1);
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
invokeId, "GracefulFallbackPromise: I was the fastest, so I will attempt to notify discord users before resolving with a call"
|
invokeId + " GracefulFallbackPromise: I was the fastest, so I will attempt to notify discord users before resolving with a call"
|
||||||
);
|
);
|
||||||
await notifyAllDiscord(
|
await notifyAllDiscord(
|
||||||
context,
|
context,
|
||||||
@ -120,10 +120,10 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
|||||||
resolve(twiml);
|
resolve(twiml);
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
invokeId, "GracefulFallbackPromise: dropping out of the race, unlock is already notifying discord users"
|
invokeId + " GracefulFallbackPromise: dropping out of the race, unlock is already notifying discord users"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, 8000));
|
}, 7500));
|
||||||
});
|
});
|
||||||
|
|
||||||
const ungracefulFallbackPromise = new Promise<VoiceResponse>((resolve, reject) => {
|
const ungracefulFallbackPromise = new Promise<VoiceResponse>((resolve, reject) => {
|
||||||
@ -136,14 +136,14 @@ export const handler: ServerlessFunctionSignature<TwilioContext, BuzzerDialEvent
|
|||||||
|
|
||||||
const twiml = dialFallbackTwiml(config);
|
const twiml = dialFallbackTwiml(config);
|
||||||
console.log(
|
console.log(
|
||||||
invokeId, "UngracefulFallbackPromise: Cutting it too close to timeout! Skipping notifying users and calling fallback"
|
invokeId + " UngracefulFallbackPromise: Cutting it too close to timeout! Skipping notifying users and calling fallback"
|
||||||
);
|
);
|
||||||
resolve(twiml);
|
resolve(twiml);
|
||||||
}, 9000));
|
}, 8500));
|
||||||
});
|
});
|
||||||
|
|
||||||
const twiml = await Promise.race([unlockPromise, gracefulFallbackPromise, ungracefulFallbackPromise]);
|
const twiml = await Promise.race([unlockPromise, gracefulFallbackPromise, ungracefulFallbackPromise]);
|
||||||
console.log(invokeId, "Race ended, clearing residual timers");
|
console.log(invokeId + " Race ended, clearing residual timers");
|
||||||
timeouts.forEach(timeout => clearTimeout(timeout));
|
timeouts.forEach(timeout => clearTimeout(timeout));
|
||||||
intervals.forEach(interval => clearInterval(interval));
|
intervals.forEach(interval => clearInterval(interval));
|
||||||
callback(null, twiml);
|
callback(null, twiml);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user