I am in dire need of help. I dont know when this error arises as I am unable to reproduce this bug on my own. Our center of attention is ServiceToService.setClientLoggingInResponse() method (which is called from RequestProcessor class line:12) . I have log printing the following output from bottom to top. We see memcache error on third logged statement. It occurs in MCache.readFromCache() method then it goes to catch block of RequestProcessor class (line 15 of RequestProcessor class). I am unable to comprehend why it is in catch block of RequestProcessor. Because I thought I have everything cover in setClientLoggingInResponse(). I thought if memcache error arises it should go to line 48 in setClientLoggingInResponse() method. But as log shows it didn’t. I have two questions.
- Why it didn’t end up in line 48 in setClientLoggingInResponse() method but rather end up in catch block (line 15 of RequestProcessor class)
- What should I do so that it stays in setClientLoggingInResponse() and does only this memory.addToMemory(locationUuid, {})
LOGS
<code>2024-05-30 21:18:45
{"level":100,"time":1717085925098,"pid":19,"hostname":"","msg":"preparing error response","method":"RequestProcessor.prepareErrorResponse"}
{"level":600,"time":1717085925098,"pid":19,"hostname":"","msg":"failed to process request","method":"RequestProcessor.process"}
{"level":400,"time":1717085925097,"pid":19,"hostname":"","msg":"memcache error: Server at kvs-memcached-client-logging:11211 not available while reading key=5c6c2ac0-1e7e-11ef-bc70-dba3d3ca35f7","method":"Client.<anonymous>"}
{"level":100,"time":1717085925097,"pid":19,"hostname":"","msg":"Data is not in memory for:","method":"ServiceToService.setClientLoggingInResponse"}
{"level":100,"time":1717085925097,"pid":19,"hostname":"","msg":"setClientLoggingInResponse","method":"ServiceToService.setClientLoggingInResponse"}
<code>2024-05-30 21:18:45
{"level":100,"time":1717085925098,"pid":19,"hostname":"","msg":"preparing error response","method":"RequestProcessor.prepareErrorResponse"}
2024-05-30 21:18:45
{"level":600,"time":1717085925098,"pid":19,"hostname":"","msg":"failed to process request","method":"RequestProcessor.process"}
2024-05-30 21:18:45
{"level":400,"time":1717085925097,"pid":19,"hostname":"","msg":"memcache error: Server at kvs-memcached-client-logging:11211 not available while reading key=5c6c2ac0-1e7e-11ef-bc70-dba3d3ca35f7","method":"Client.<anonymous>"}
2024-05-30 21:18:45
{"level":100,"time":1717085925097,"pid":19,"hostname":"","msg":"Data is not in memory for:","method":"ServiceToService.setClientLoggingInResponse"}
2024-05-30 21:18:45
{"level":100,"time":1717085925097,"pid":19,"hostname":"","msg":"setClientLoggingInResponse","method":"ServiceToService.setClientLoggingInResponse"}
</code>
2024-05-30 21:18:45
{"level":100,"time":1717085925098,"pid":19,"hostname":"","msg":"preparing error response","method":"RequestProcessor.prepareErrorResponse"}
2024-05-30 21:18:45
{"level":600,"time":1717085925098,"pid":19,"hostname":"","msg":"failed to process request","method":"RequestProcessor.process"}
2024-05-30 21:18:45
{"level":400,"time":1717085925097,"pid":19,"hostname":"","msg":"memcache error: Server at kvs-memcached-client-logging:11211 not available while reading key=5c6c2ac0-1e7e-11ef-bc70-dba3d3ca35f7","method":"Client.<anonymous>"}
2024-05-30 21:18:45
{"level":100,"time":1717085925097,"pid":19,"hostname":"","msg":"Data is not in memory for:","method":"ServiceToService.setClientLoggingInResponse"}
2024-05-30 21:18:45
{"level":100,"time":1717085925097,"pid":19,"hostname":"","msg":"setClientLoggingInResponse","method":"ServiceToService.setClientLoggingInResponse"}
RequestProcessor Class
<code>class RequestProcessor {
static async process(requestOptions, tick = () => {}, ignoreAppKeyValidation) {
const uniqueTimerIds = RequestProcessor.createUniqueTimerIds();
_.set(requestOptions, 'uniqueTimerIds', uniqueTimerIds);
tick('before RequestProcessor.callService...');
await RequestProcessor.callService(requestOptions, tick);
tick('after RequestProcessor.callService...');
await RequestProcessor.setClientLoggingInResponse(requestOptions);
RequestProcessor.prepareResponse(requestOptions);
logger.error('failed to process request', { error: error.message });
RequestProcessor.prepareErrorResponse(requestOptions, error.message, error.errorCode);
LoggerStatus.tokenLogger(requestOptions, metrics);
static async callService(requestOptions, tick) {
await serviceToService.callService(requestOptions, tick);
static prepareResponse(requestOptions) {
logger.debug('preparing response', { payload: requestOptions.payload });
serviceToService.prepareResponse(requestOptions);
static prepareErrorResponse(requestOptions, errorText, errorCode) {
logger.debug('preparing error response', { errorText, errorCode, payload: requestOptions.payload });
serviceToService.prepareErrorResponse(requestOptions, errorText, errorCode);
static async setClientLoggingInResponse(requestOptions) {
await serviceToService.setClientLoggingInResponse(requestOptions);
RequestProcessor.serviceToService = serviceToService;
module.exports = RequestProcessor;
<code>class RequestProcessor {
static async process(requestOptions, tick = () => {}, ignoreAppKeyValidation) {
const uniqueTimerIds = RequestProcessor.createUniqueTimerIds();
_.set(requestOptions, 'uniqueTimerIds', uniqueTimerIds);
try {
tick('before RequestProcessor.callService...');
await RequestProcessor.callService(requestOptions, tick);
tick('after RequestProcessor.callService...');
await RequestProcessor.setClientLoggingInResponse(requestOptions);
RequestProcessor.prepareResponse(requestOptions);
} catch (error) {
logger.error('failed to process request', { error: error.message });
RequestProcessor.prepareErrorResponse(requestOptions, error.message, error.errorCode);
}
LoggerStatus.tokenLogger(requestOptions, metrics);
}
static async callService(requestOptions, tick) {
await serviceToService.callService(requestOptions, tick);
}
static prepareResponse(requestOptions) {
logger.debug('preparing response', { payload: requestOptions.payload });
serviceToService.prepareResponse(requestOptions);
}
static prepareErrorResponse(requestOptions, errorText, errorCode) {
logger.debug('preparing error response', { errorText, errorCode, payload: requestOptions.payload });
serviceToService.prepareErrorResponse(requestOptions, errorText, errorCode);
}
static async setClientLoggingInResponse(requestOptions) {
await serviceToService.setClientLoggingInResponse(requestOptions);
}
}
RequestProcessor.serviceToService = serviceToService;
module.exports = RequestProcessor;
</code>
class RequestProcessor {
static async process(requestOptions, tick = () => {}, ignoreAppKeyValidation) {
const uniqueTimerIds = RequestProcessor.createUniqueTimerIds();
_.set(requestOptions, 'uniqueTimerIds', uniqueTimerIds);
try {
tick('before RequestProcessor.callService...');
await RequestProcessor.callService(requestOptions, tick);
tick('after RequestProcessor.callService...');
await RequestProcessor.setClientLoggingInResponse(requestOptions);
RequestProcessor.prepareResponse(requestOptions);
} catch (error) {
logger.error('failed to process request', { error: error.message });
RequestProcessor.prepareErrorResponse(requestOptions, error.message, error.errorCode);
}
LoggerStatus.tokenLogger(requestOptions, metrics);
}
static async callService(requestOptions, tick) {
await serviceToService.callService(requestOptions, tick);
}
static prepareResponse(requestOptions) {
logger.debug('preparing response', { payload: requestOptions.payload });
serviceToService.prepareResponse(requestOptions);
}
static prepareErrorResponse(requestOptions, errorText, errorCode) {
logger.debug('preparing error response', { errorText, errorCode, payload: requestOptions.payload });
serviceToService.prepareErrorResponse(requestOptions, errorText, errorCode);
}
static async setClientLoggingInResponse(requestOptions) {
await serviceToService.setClientLoggingInResponse(requestOptions);
}
}
RequestProcessor.serviceToService = serviceToService;
module.exports = RequestProcessor;
ServiceToService Class
<code>class ServiceToService {
async setClientLoggingInResponse(requestOptions) {
const { payload } = requestOptions;
logger.debug(`setClientLoggingInResponse`, payload);
if (this.CLIENT_LOGGING_ENABLE && payload.access && payload.access.location && payload.access.location.uuid) {
const locationUuid = payload.access.location.uuid;
if (!memory.getFromMemory(locationUuid)) {
logger.debug(`Data is not in memory for:`, locationUuid);
const cacheKey = locationUuid;
const timer = new Promise(resolve => setTimeout(resolve, this.CLIENT_LOGGING_MAX_READ_TIME_MS));
const readFromCache = cache.readFromCache(cacheKey);
const result = await Promise.race([timer, readFromCache]);
logger.debug(`Won Race, Result found for:`, { locationUuid, result });
cachedData = JSON.parse(result);
memory.addToMemory(locationUuid, cachedData)
logger.info(`JSON decoding error: ${jsonError.message}`);
memory.addToMemory(locationUuid, cachedData)
readFromCache.then(function(result) //whenever response finishes after losing race condition with timer, store in memory the value as described below
logger.debug(`Lost Race, Result found for:`, { locationUuid, result });
cachedData = JSON.parse(result); // if result is not found (undefined) still catch will run and {} will store
memory.addToMemory(locationUuid, cachedData)
logger.info(`JSON decoding error: ${jsonError.message}`);
memory.addToMemory(locationUuid, {})
logger.info(`Error while reading memcache:`);
memory.addToMemory(locationUuid, {})
let obj = memory.getFromMemory(locationUuid); // need to make fresh call in case above process has set the object
if (obj && Object.keys(obj).length > 0) { // if object is not empty ({})
logger.debug(`Found locationUuid=${locationUuid} in memory with value=`, obj);
requestOptions.response._client_logging = obj;
memory.addToMemory(locationUuid, {}); // point 4 of spec IMPORTANT
logger.debug(`Eception in setClientLoggingInResponse ${JSON.stringify(e)}`);
module.exports = ServiceToService;
<code>class ServiceToService {
constructor() {
// statments
}
async setClientLoggingInResponse(requestOptions) {
const { payload } = requestOptions;
logger.debug(`setClientLoggingInResponse`, payload);
let cachedData = {};
try {
if (this.CLIENT_LOGGING_ENABLE && payload.access && payload.access.location && payload.access.location.uuid) {
const locationUuid = payload.access.location.uuid;
if (!memory.getFromMemory(locationUuid)) {
logger.debug(`Data is not in memory for:`, locationUuid);
const cacheKey = locationUuid;
const timer = new Promise(resolve => setTimeout(resolve, this.CLIENT_LOGGING_MAX_READ_TIME_MS));
const readFromCache = cache.readFromCache(cacheKey);
const result = await Promise.race([timer, readFromCache]);
if (result) {
logger.debug(`Won Race, Result found for:`, { locationUuid, result });
try {
cachedData = JSON.parse(result);
memory.addToMemory(locationUuid, cachedData)
} catch (jsonError) {
logger.info(`JSON decoding error: ${jsonError.message}`);
cachedData = {};
memory.addToMemory(locationUuid, cachedData)
}
}
else
{
readFromCache.then(function(result) //whenever response finishes after losing race condition with timer, store in memory the value as described below
{
logger.debug(`Lost Race, Result found for:`, { locationUuid, result });
try {
cachedData = JSON.parse(result); // if result is not found (undefined) still catch will run and {} will store
memory.addToMemory(locationUuid, cachedData)
} catch (jsonError) {
logger.info(`JSON decoding error: ${jsonError.message}`);
memory.addToMemory(locationUuid, {})
}
}).catch(function(e){
logger.info(`Error while reading memcache:`);
memory.addToMemory(locationUuid, {})
});
}
}
let obj = memory.getFromMemory(locationUuid); // need to make fresh call in case above process has set the object
if (obj && Object.keys(obj).length > 0) { // if object is not empty ({})
logger.debug(`Found locationUuid=${locationUuid} in memory with value=`, obj);
requestOptions.response._client_logging = obj;
}
}
}
catch(e)
{
memory.addToMemory(locationUuid, {}); // point 4 of spec IMPORTANT
logger.debug(`Eception in setClientLoggingInResponse ${JSON.stringify(e)}`);
}
}
}
module.exports = ServiceToService;
</code>
class ServiceToService {
constructor() {
// statments
}
async setClientLoggingInResponse(requestOptions) {
const { payload } = requestOptions;
logger.debug(`setClientLoggingInResponse`, payload);
let cachedData = {};
try {
if (this.CLIENT_LOGGING_ENABLE && payload.access && payload.access.location && payload.access.location.uuid) {
const locationUuid = payload.access.location.uuid;
if (!memory.getFromMemory(locationUuid)) {
logger.debug(`Data is not in memory for:`, locationUuid);
const cacheKey = locationUuid;
const timer = new Promise(resolve => setTimeout(resolve, this.CLIENT_LOGGING_MAX_READ_TIME_MS));
const readFromCache = cache.readFromCache(cacheKey);
const result = await Promise.race([timer, readFromCache]);
if (result) {
logger.debug(`Won Race, Result found for:`, { locationUuid, result });
try {
cachedData = JSON.parse(result);
memory.addToMemory(locationUuid, cachedData)
} catch (jsonError) {
logger.info(`JSON decoding error: ${jsonError.message}`);
cachedData = {};
memory.addToMemory(locationUuid, cachedData)
}
}
else
{
readFromCache.then(function(result) //whenever response finishes after losing race condition with timer, store in memory the value as described below
{
logger.debug(`Lost Race, Result found for:`, { locationUuid, result });
try {
cachedData = JSON.parse(result); // if result is not found (undefined) still catch will run and {} will store
memory.addToMemory(locationUuid, cachedData)
} catch (jsonError) {
logger.info(`JSON decoding error: ${jsonError.message}`);
memory.addToMemory(locationUuid, {})
}
}).catch(function(e){
logger.info(`Error while reading memcache:`);
memory.addToMemory(locationUuid, {})
});
}
}
let obj = memory.getFromMemory(locationUuid); // need to make fresh call in case above process has set the object
if (obj && Object.keys(obj).length > 0) { // if object is not empty ({})
logger.debug(`Found locationUuid=${locationUuid} in memory with value=`, obj);
requestOptions.response._client_logging = obj;
}
}
}
catch(e)
{
memory.addToMemory(locationUuid, {}); // point 4 of spec IMPORTANT
logger.debug(`Eception in setClientLoggingInResponse ${JSON.stringify(e)}`);
}
}
}
module.exports = ServiceToService;
MCache Class
<code>const config = require('../config');
const Memcached = require('memcached');
const { logger } = require('logger-wrapper');
constructor({ memcached }) {
this.memcached = memcached;
this.readFromCache = this.readFromCache.bind(this);
this.writeToCache = this.writeToCache.bind(this);
async readFromCache(key) {
return new Promise((resolve, reject) => {
this.memcached.get(key, (err, data) => {
logger.warning(`memcache error: ${err.message} while reading key=${key}`);
const memcached = new Memcached(`${config.get('MEMCACHED_HOST')}:${config.get('MEMCACHED_PORT')}`);
const mCache = new MCache({ memcached });
<code>const config = require('../config');
const Memcached = require('memcached');
const { logger } = require('logger-wrapper');
class MCache {
constructor({ memcached }) {
this.memcached = memcached;
this.readFromCache = this.readFromCache.bind(this);
this.writeToCache = this.writeToCache.bind(this);
}
async readFromCache(key) {
return new Promise((resolve, reject) => {
this.memcached.get(key, (err, data) => {
if (err) {
logger.warning(`memcache error: ${err.message} while reading key=${key}`);
reject(err);
}
resolve(data);
});
});
}
// other methods
}
const memcached = new Memcached(`${config.get('MEMCACHED_HOST')}:${config.get('MEMCACHED_PORT')}`);
const mCache = new MCache({ memcached });
module.exports = mCache;
</code>
const config = require('../config');
const Memcached = require('memcached');
const { logger } = require('logger-wrapper');
class MCache {
constructor({ memcached }) {
this.memcached = memcached;
this.readFromCache = this.readFromCache.bind(this);
this.writeToCache = this.writeToCache.bind(this);
}
async readFromCache(key) {
return new Promise((resolve, reject) => {
this.memcached.get(key, (err, data) => {
if (err) {
logger.warning(`memcache error: ${err.message} while reading key=${key}`);
reject(err);
}
resolve(data);
});
});
}
// other methods
}
const memcached = new Memcached(`${config.get('MEMCACHED_HOST')}:${config.get('MEMCACHED_PORT')}`);
const mCache = new MCache({ memcached });
module.exports = mCache;