@itentialopensource/adapter-utils 5.10.6 → 5.10.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cacheHandler.js +245 -181
- package/package.json +1 -1
package/lib/cacheHandler.js
CHANGED
|
@@ -43,7 +43,12 @@ function deleteCacheData(cacheHandler) {
|
|
|
43
43
|
|
|
44
44
|
const handler = cacheHandler;
|
|
45
45
|
|
|
46
|
-
//
|
|
46
|
+
// Log INFO level if cache is disabled
|
|
47
|
+
if (!handler.enabled) {
|
|
48
|
+
log.info(`${origin}: Cache is turned off.`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Get all keys to ensure nothing else is editing the cache at this time
|
|
47
52
|
const keysArr = [];
|
|
48
53
|
handler.cache.forEach((entity) => {
|
|
49
54
|
keysArr.push(entity.lockKey);
|
|
@@ -51,12 +56,18 @@ function deleteCacheData(cacheHandler) {
|
|
|
51
56
|
|
|
52
57
|
lock.acquire(keysArr, () => {
|
|
53
58
|
if (!handler.enabled) {
|
|
59
|
+
// Clear cache and log once when going from enabled to disabled
|
|
60
|
+
if (handler.cache.length > 0 || handler.propertiesMap.size > 0) {
|
|
61
|
+
log.info(`${origin}: Cache has been cleared.`);
|
|
62
|
+
}
|
|
63
|
+
|
|
54
64
|
handler.cache.forEach((entity) => {
|
|
55
65
|
clearInterval(entity.intervalId);
|
|
56
66
|
});
|
|
57
67
|
handler.cache = [];
|
|
58
68
|
handler.propertiesMap.clear();
|
|
59
|
-
|
|
69
|
+
} else {
|
|
70
|
+
log.debug(`${origin}: Cache is currently enabled.`);
|
|
60
71
|
}
|
|
61
72
|
});
|
|
62
73
|
}
|
|
@@ -132,79 +143,91 @@ function validateProperties(obj) {
|
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
const props = obj;
|
|
135
|
-
|
|
146
|
+
|
|
147
|
+
// Check cache, cache.enabled, cache.entities exist
|
|
136
148
|
if (!props.cache) {
|
|
137
|
-
//
|
|
149
|
+
// No cache, initialize default props
|
|
138
150
|
props.cache = {
|
|
139
151
|
enabled: false,
|
|
140
152
|
entities: []
|
|
141
153
|
};
|
|
142
154
|
} else {
|
|
143
155
|
if (!props.cache.enabled) {
|
|
156
|
+
log.info(`${origin}: Cache is turned off.`);
|
|
144
157
|
props.cache.enabled = false;
|
|
145
|
-
log.error(`${origin}: Passed in cache properties but did not specify enabled!`);
|
|
146
158
|
}
|
|
147
|
-
|
|
159
|
+
|
|
160
|
+
if (props.cache.enabled && !props.cache.entities) {
|
|
148
161
|
props.cache.entities = [];
|
|
149
|
-
log.
|
|
162
|
+
log.info(`${origin}: Cache entities initialized as an empty array.`);
|
|
150
163
|
}
|
|
151
164
|
}
|
|
152
|
-
// check each entity type in entities
|
|
153
|
-
for (let i = 0; i < props.cache.entities.length; i += 1) {
|
|
154
|
-
// must have entityType and populate
|
|
155
|
-
if (!props.cache.entities[i].entityType || !props.cache.entities[i].populate || props.cache.entities[i].populate.length === 0) {
|
|
156
|
-
log.warn(`${origin}: removed invalid cache property at index ${i}`);
|
|
157
|
-
// remove rather than throw error
|
|
158
|
-
props.cache.entities.splice(i, 1);
|
|
159
|
-
i -= 1; // already pointing at next after splice
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
165
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
166
|
+
// Validate each entity in cache.entities if cache is enabled
|
|
167
|
+
if (props.cache.enabled) {
|
|
168
|
+
for (let i = 0; i < props.cache.entities.length; i += 1) {
|
|
169
|
+
const entity = props.cache.entities[i];
|
|
170
|
+
|
|
171
|
+
// Ensure entityType and populate exist and are valid
|
|
172
|
+
if (!entity.entityType || !entity.populate || entity.populate.length === 0) {
|
|
173
|
+
log.warn(`${origin}: Removed invalid cache property at index ${i}`);
|
|
174
|
+
props.cache.entities.splice(i, 1);
|
|
175
|
+
i -= 1; // Adjust index after removal
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
173
178
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
// Validate frequency (default: 24 hrs, min: 15 mins, max: 1 week)
|
|
180
|
+
if (!entity.frequency) {
|
|
181
|
+
entity.frequency = 24 * 60; // Default to 1 day in minutes
|
|
182
|
+
log.debug(`${origin}: Frequency set to default (1440 minutes).`);
|
|
183
|
+
} else if (entity.frequency < 15) {
|
|
184
|
+
log.warn(`${origin}: Frequency ${entity.frequency} too small! Adjusted to 15 minutes.`);
|
|
185
|
+
entity.frequency = 15;
|
|
186
|
+
} else if (entity.frequency > 10080) {
|
|
187
|
+
log.warn(`${origin}: Frequency ${entity.frequency} too large! Adjusted to 1 week.`);
|
|
188
|
+
entity.frequency = 10080;
|
|
189
|
+
}
|
|
178
190
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
// Default flushOnFail = false
|
|
192
|
+
if (entity.flushOnFail === undefined) {
|
|
193
|
+
entity.flushOnFail = false;
|
|
194
|
+
log.debug(`${origin}: flushOnFail defaulted to false.`);
|
|
195
|
+
}
|
|
183
196
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
197
|
+
// Default limit = 1000
|
|
198
|
+
if (!entity.limit) {
|
|
199
|
+
entity.limit = 1000;
|
|
200
|
+
log.debug(`${origin}: Limit defaulted to 1000.`);
|
|
201
|
+
}
|
|
187
202
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const curTask = cacheTask; // for lint
|
|
194
|
-
if (!curTask.name) {
|
|
195
|
-
log.error('Cached task has no task name!');
|
|
196
|
-
curTask.name = ''; // prevent errors, will not ever match a task name
|
|
197
|
-
}
|
|
198
|
-
if (!curTask.filterField) {
|
|
199
|
-
// if no filter then assume is a get all call, would need to explicitly check this
|
|
200
|
-
curTask.filterField = '';
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}
|
|
203
|
+
// Default retryAttempts = 5
|
|
204
|
+
if (!entity.retryAttempts) {
|
|
205
|
+
entity.retryAttempts = 5; // Used for startup retries
|
|
206
|
+
log.debug(`${origin}: retryAttempts defaulted to 5.`);
|
|
207
|
+
}
|
|
204
208
|
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
// Validate cachedTasks
|
|
210
|
+
if (!entity.cachedTasks) {
|
|
211
|
+
entity.cachedTasks = [];
|
|
212
|
+
log.debug(`${origin}: cachedTasks initialized as an empty array.`);
|
|
213
|
+
} else {
|
|
214
|
+
entity.cachedTasks.forEach((cacheTask, idx) => {
|
|
215
|
+
const curTask = cacheTask; // for lint
|
|
216
|
+
if (!cacheTask.name) {
|
|
217
|
+
log.error(`${origin}: Cached task at index ${idx} has no name! Defaulting to an empty string.`);
|
|
218
|
+
curTask.name = ''; // Prevent errors, will not match a task name
|
|
219
|
+
}
|
|
220
|
+
if (!cacheTask.filterField) {
|
|
221
|
+
curTask.filterField = ''; // Assume a "get all" call if no filter specified
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Fill in missing populate fields
|
|
227
|
+
validatePopulate(entity.populate);
|
|
228
|
+
}
|
|
207
229
|
}
|
|
230
|
+
|
|
208
231
|
return props;
|
|
209
232
|
}
|
|
210
233
|
|
|
@@ -337,15 +360,20 @@ function removeCacheEntry(cache, entityType) {
|
|
|
337
360
|
|
|
338
361
|
for (let i = 0; i < cache.length; i += 1) {
|
|
339
362
|
if (cache[i].entityType === entityType) {
|
|
363
|
+
log.debug(`${origin}: Found entity type '${entityType}' in cache. Attempting to remove.`);
|
|
364
|
+
|
|
340
365
|
lock.acquire(cache[i].lockKey, () => {
|
|
366
|
+
log.debug(`${origin}: Lock acquired for entity type '${entityType}'. Clearing interval and removing from cache.`);
|
|
341
367
|
clearInterval(cache[i].intervalId);
|
|
342
|
-
cache
|
|
368
|
+
cache.splice(i, 1);
|
|
343
369
|
});
|
|
344
|
-
|
|
370
|
+
|
|
371
|
+
log.info(`${origin}: Successfully removed '${entityType}' from cache.`);
|
|
345
372
|
return;
|
|
346
373
|
}
|
|
347
374
|
}
|
|
348
|
-
|
|
375
|
+
|
|
376
|
+
log.error(`${origin}: Entity type '${entityType}' not found in cache. Removal failed.`);
|
|
349
377
|
}
|
|
350
378
|
|
|
351
379
|
/**
|
|
@@ -477,76 +505,92 @@ class CacheHandler {
|
|
|
477
505
|
return;
|
|
478
506
|
}
|
|
479
507
|
|
|
508
|
+
log.debug(`${origin}: Validating and setting new properties.`);
|
|
480
509
|
this.props = validateProperties(properties);
|
|
481
510
|
|
|
482
511
|
const wasEnabled = this.enabled || false; // in case undefined
|
|
483
512
|
this.enabled = this.props.cache.enabled;
|
|
513
|
+
|
|
484
514
|
if (!this.enabled) {
|
|
485
|
-
// destroy cache and properties for memory efficiency
|
|
486
515
|
if (wasEnabled) {
|
|
516
|
+
log.warn(`${origin}: Cache was disabled from enabled state. Clearing cache for memory efficiency.`);
|
|
487
517
|
deleteCacheData(this);
|
|
488
518
|
} else {
|
|
489
519
|
log.debug(`${origin}: Cache remains disabled. No action required.`);
|
|
490
520
|
}
|
|
491
|
-
log.warn('Cache was disabled from enabled, removed cache memory.');
|
|
492
521
|
return;
|
|
493
522
|
}
|
|
494
523
|
|
|
495
|
-
|
|
524
|
+
log.debug(`${origin}: Checking for deleted or updated entity types.`);
|
|
496
525
|
this.propertiesMap.forEach((value, key) => {
|
|
526
|
+
let entityExists = false;
|
|
527
|
+
|
|
497
528
|
for (let i = 0; i < this.props.cache.entities.length; i += 1) {
|
|
498
|
-
if (
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
log.warn(`${origin}: Removed cache entity type due to change in properties.`);
|
|
502
|
-
log.info(`Deleted props for entity type ${key} with val ${value}`);
|
|
503
|
-
return; // continue forEach
|
|
529
|
+
if (this.props.cache.entities[i].name === key) {
|
|
530
|
+
entityExists = true;
|
|
531
|
+
break;
|
|
504
532
|
}
|
|
505
533
|
}
|
|
534
|
+
|
|
535
|
+
if (!entityExists) {
|
|
536
|
+
log.warn(`${origin}: Detected removed entity type '${key}'. Removing from cache.`);
|
|
537
|
+
removeCacheEntry(this.cache, key);
|
|
538
|
+
this.propertiesMap.delete(key);
|
|
539
|
+
log.info(`${origin}: Deleted properties for entity type '${key}' with value '${value}'.`);
|
|
540
|
+
}
|
|
506
541
|
});
|
|
507
542
|
|
|
508
|
-
|
|
543
|
+
log.debug(`${origin}: Updating and setting properties map for cache entities.`);
|
|
509
544
|
this.props.cache.entities.forEach((entity) => {
|
|
510
545
|
if (!this.propertiesMap.has(entity.entityType)) {
|
|
511
|
-
|
|
546
|
+
log.debug(`${origin}: Adding new entity type '${entity.entityType}' to properties map.`);
|
|
512
547
|
this.propertiesMap.set(entity.entityType, {});
|
|
513
|
-
this.propertiesMap.get(entity.entityType)
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
548
|
+
const entityProps = this.propertiesMap.get(entity.entityType);
|
|
549
|
+
entityProps.frequency = entity.frequency;
|
|
550
|
+
entityProps.flushOnFail = entity.flushOnFail;
|
|
551
|
+
entityProps.populate = entity.populate;
|
|
552
|
+
entityProps.limit = entity.limit;
|
|
553
|
+
entityProps.retryAttempts = entity.retryAttempts;
|
|
518
554
|
|
|
519
555
|
const newIntervalId = setInterval(() => {
|
|
556
|
+
log.debug(`${origin}: Populating cache for entity type '${entity.entityType}'.`);
|
|
520
557
|
this.populateCache(entity.entityType);
|
|
521
558
|
}, entity.frequency * 60000);
|
|
522
559
|
|
|
523
560
|
const sort = Object.prototype.hasOwnProperty.call(entity, 'sort') ? entity.sort : true; // default true
|
|
524
561
|
this.cache.push(createCacheEntity(entity.entityType, null, newIntervalId, sort));
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
562
|
+
|
|
563
|
+
this.populateCache(entity.entityType)
|
|
564
|
+
.then((result) => {
|
|
565
|
+
if (result && result[0] === 'error') {
|
|
566
|
+
log.warn(`${origin}: Populate failed for '${entity.entityType}'. Retrying...`);
|
|
567
|
+
retryPopulate(entity.entityType, this, entity.retryAttempts).then((nextResult) => {
|
|
568
|
+
log.info(`${origin}: Retry result for '${entity.entityType}': ${nextResult}`);
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
})
|
|
572
|
+
.catch((error) => {
|
|
573
|
+
log.error(`${origin}: Populate cache failed for '${entity.entityType}'.`);
|
|
574
|
+
if (error.icode === 'AD.301') {
|
|
575
|
+
log.error(`${origin}: Clearing interval and removing cache entity '${entity.entityType}' due to error.`);
|
|
576
|
+
clearInterval(newIntervalId);
|
|
577
|
+
this.cache.removeCacheEntry(this.cache, entity.entityType);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
539
580
|
} else {
|
|
540
|
-
|
|
541
|
-
|
|
581
|
+
log.debug(`${origin}: Updating frequency and properties for existing entity type '${entity.entityType}'.`);
|
|
582
|
+
const entityProps = this.propertiesMap.get(entity.entityType);
|
|
583
|
+
|
|
584
|
+
if (entity.frequency !== entityProps.frequency) {
|
|
585
|
+
log.info(`${origin}: Updating update frequency for '${entity.entityType}' from '${entityProps.frequency}' to '${entity.frequency}'.`);
|
|
542
586
|
changeUpdateFrequency(this.cache, entity.entityType, entity.frequency, this);
|
|
543
587
|
}
|
|
544
588
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
589
|
+
entityProps.frequency = entity.frequency;
|
|
590
|
+
entityProps.flushOnFail = entity.flushOnFail;
|
|
591
|
+
entityProps.populate = entity.populate;
|
|
592
|
+
entityProps.limit = entity.limit;
|
|
593
|
+
entityProps.retryAttempts = entity.retryAttempts;
|
|
550
594
|
}
|
|
551
595
|
});
|
|
552
596
|
}
|
|
@@ -563,37 +607,37 @@ class CacheHandler {
|
|
|
563
607
|
log.trace(origin);
|
|
564
608
|
|
|
565
609
|
if (!this.enabled) {
|
|
610
|
+
log.info(`${origin}: Cache is not enabled. Populate operation aborted.`);
|
|
566
611
|
return Promise.reject(new Error('Cache is not enabled!'));
|
|
567
612
|
}
|
|
568
613
|
|
|
569
|
-
log.info(
|
|
614
|
+
log.info(`${origin}: Starting cache population.`);
|
|
570
615
|
|
|
571
|
-
//
|
|
616
|
+
// Support string and array input
|
|
572
617
|
let entityArr = entities;
|
|
573
618
|
if (!Array.isArray(entities)) {
|
|
574
619
|
entityArr = [entities];
|
|
575
620
|
}
|
|
576
621
|
|
|
577
|
-
//
|
|
622
|
+
// Ensure all entities are tracked
|
|
578
623
|
for (let i = 0; i < entityArr.length; i += 1) {
|
|
579
624
|
const entityType = entityArr[i];
|
|
580
625
|
if (!this.propertiesMap.has(entityType)) {
|
|
581
|
-
log.error(`${entityType} is an untracked entity type! Check properties.`);
|
|
626
|
+
log.error(`${origin}: ${entityType} is an untracked entity type! Check properties.`);
|
|
582
627
|
return Promise.reject(new Error(`${entityType} is an untracked entity type! Check properties.`));
|
|
583
628
|
}
|
|
584
629
|
}
|
|
585
630
|
|
|
586
631
|
try {
|
|
587
632
|
const promiseArr = [];
|
|
588
|
-
//
|
|
633
|
+
// Populate each entity type
|
|
589
634
|
for (let j = 0; j < entityArr.length; j += 1) {
|
|
590
635
|
const entityType = entityArr[j];
|
|
591
|
-
// try to find current entityType in cache
|
|
592
636
|
for (let i = 0; i < this.cache.length; i += 1) {
|
|
593
|
-
if (this.cache[i].entityType === entityType) {
|
|
637
|
+
if (this.cache[i].entityType === entityType) {
|
|
594
638
|
promiseArr.push(new Promise((resolve, reject) => {
|
|
595
639
|
makeIAPCall(this.propertiesMap.get(entityType).populate, this.requestHandler, (cacheData, error) => {
|
|
596
|
-
//
|
|
640
|
+
// Error handling
|
|
597
641
|
let errorMsg = null;
|
|
598
642
|
if (error) {
|
|
599
643
|
errorMsg = `${origin}: ${entityType} failed with error ${error.IAPerror.displayString}.`;
|
|
@@ -602,17 +646,12 @@ class CacheHandler {
|
|
|
602
646
|
} else if (cacheData.length === 0) {
|
|
603
647
|
errorMsg = `${origin}: ${entityType} failed. Nothing found.`;
|
|
604
648
|
}
|
|
605
|
-
// handle error
|
|
606
|
-
if (errorMsg !== null) {
|
|
607
|
-
/**
|
|
608
|
-
* removed unnecessary check if cache[i].list is null here
|
|
609
|
-
* setting null var to null again is fine and shortens critical section
|
|
610
|
-
* */
|
|
611
649
|
|
|
650
|
+
if (errorMsg !== null) {
|
|
612
651
|
if (this.propertiesMap.get(entityType).flushOnFail) {
|
|
613
652
|
lock.acquire(this.cache[i].lockKey, (done) => {
|
|
614
653
|
this.cache[i].list = null;
|
|
615
|
-
done(`${errorMsg}
|
|
654
|
+
done(`${errorMsg} Cache flushed.`);
|
|
616
655
|
}, (ret) => {
|
|
617
656
|
log.error(ret);
|
|
618
657
|
});
|
|
@@ -620,24 +659,22 @@ class CacheHandler {
|
|
|
620
659
|
log.error(`${errorMsg} Keeping old data.`);
|
|
621
660
|
}
|
|
622
661
|
|
|
623
|
-
// bad path
|
|
624
662
|
if (error && error.icode === 'AD.301') {
|
|
625
663
|
return reject(error);
|
|
626
664
|
}
|
|
627
665
|
return resolve('error');
|
|
628
666
|
}
|
|
629
|
-
|
|
667
|
+
|
|
668
|
+
// Sort and update cache
|
|
630
669
|
if (this.cache[i].sort) {
|
|
631
670
|
cacheData.sort(compareByName);
|
|
632
671
|
}
|
|
633
|
-
|
|
634
|
-
// no error, edit cache
|
|
635
672
|
lock.acquire(this.cache[i].lockKey, (done) => {
|
|
636
|
-
if (this.enabled) {
|
|
673
|
+
if (this.enabled) {
|
|
637
674
|
this.cache[i].list = cacheData;
|
|
638
|
-
done(`${
|
|
675
|
+
done(`${origin}: ${entityType} cache updated successfully.`);
|
|
639
676
|
} else {
|
|
640
|
-
done(
|
|
677
|
+
done(`${origin}: Populate cancelled due to disabled cache.`);
|
|
641
678
|
}
|
|
642
679
|
}, (ret) => {
|
|
643
680
|
log.info(ret);
|
|
@@ -649,6 +686,8 @@ class CacheHandler {
|
|
|
649
686
|
}
|
|
650
687
|
}
|
|
651
688
|
}
|
|
689
|
+
|
|
690
|
+
// Resolve all promises
|
|
652
691
|
const arr = await Promise.allSettled(promiseArr);
|
|
653
692
|
return new Promise((resolve, reject) => {
|
|
654
693
|
const valueArray = [];
|
|
@@ -661,7 +700,7 @@ class CacheHandler {
|
|
|
661
700
|
resolve(valueArray);
|
|
662
701
|
});
|
|
663
702
|
} catch (e) {
|
|
664
|
-
|
|
703
|
+
log.error(`${origin}: An exception occurred during cache population - ${e.message}`);
|
|
665
704
|
throw new Error(e);
|
|
666
705
|
}
|
|
667
706
|
}
|
|
@@ -684,47 +723,56 @@ class CacheHandler {
|
|
|
684
723
|
log.trace(origin);
|
|
685
724
|
|
|
686
725
|
if (!this.enabled) {
|
|
687
|
-
log.
|
|
726
|
+
log.info(`${origin}: Cache is not enabled!`);
|
|
688
727
|
return callback(null, 'Cache is not enabled.');
|
|
689
728
|
}
|
|
690
729
|
|
|
691
730
|
if (typeof entityType !== 'string') {
|
|
692
|
-
log.error(`${entityType} is not of type String
|
|
731
|
+
log.error(`${origin}: Invalid entityType - ${entityType} is not of type String.`);
|
|
693
732
|
return callback(null, `${entityType} is not of type String`);
|
|
694
733
|
}
|
|
695
734
|
|
|
696
735
|
try {
|
|
697
736
|
const options = validateOptions(opts); // may throw error
|
|
698
|
-
|
|
737
|
+
|
|
738
|
+
log.debug(`${origin}: Searching cache for entityType: ${entityType}.`);
|
|
739
|
+
// Search for the specified entityType in the cache
|
|
699
740
|
for (let i = 0; i < this.cache.length; i += 1) {
|
|
700
|
-
// check if entity type we care about
|
|
701
741
|
if (this.cache[i].entityType === entityType) {
|
|
702
|
-
|
|
703
|
-
|
|
742
|
+
log.info(`${origin}: Found cache entry for entityType: ${entityType}.`);
|
|
743
|
+
|
|
744
|
+
// Lock the cache entry for safe access
|
|
704
745
|
return lock.acquire(this.cache[i].lockKey, (done) => {
|
|
705
|
-
|
|
746
|
+
log.debug(`${origin}: Retrieved cache list for entityType: ${entityType}.`);
|
|
706
747
|
done(this.cache[i].list);
|
|
707
748
|
}, (ret) => {
|
|
708
|
-
// last iap call failed and flushed, attempt new iap call
|
|
709
749
|
if (!ret) {
|
|
710
|
-
|
|
750
|
+
log.warn(`${origin}: Last IAP call failed and flushed cache for ${entityType}. Attempting to repopulate.`);
|
|
751
|
+
|
|
752
|
+
// Repopulate cache and retry retrieval
|
|
711
753
|
return this.populateCache(entityType).then((result) => {
|
|
712
754
|
if (result && result[0] === 'success') {
|
|
755
|
+
log.info(`${origin}: Repopulation succeeded for ${entityType}. Retrieving updated entries.`);
|
|
713
756
|
return retrieveCacheEntriesHelper(this.cache, entityType, options, callback);
|
|
714
757
|
}
|
|
715
|
-
|
|
758
|
+
log.error(`${origin}: Repopulation failed for ${entityType}.`);
|
|
759
|
+
return callback(null, `Retrieve call for ${entityType} failed, and populate re-attempt failed.`);
|
|
760
|
+
}).catch((err) => {
|
|
761
|
+
log.error(`${origin}: Error during repopulation for ${entityType} - ${err.message}`);
|
|
762
|
+
return callback(null, `Retrieve call for ${entityType} failed due to an error during repopulation.`);
|
|
716
763
|
});
|
|
717
764
|
}
|
|
718
765
|
|
|
719
|
-
|
|
766
|
+
log.debug(`${origin}: Retrieved entries successfully for entityType: ${entityType}.`);
|
|
720
767
|
return retrieveCacheEntriesHelper(this.cache, entityType, options, callback);
|
|
721
768
|
});
|
|
722
769
|
}
|
|
723
770
|
}
|
|
724
|
-
|
|
771
|
+
|
|
772
|
+
log.error(`${origin}: Cache entry not found for entityType: ${entityType}.`);
|
|
725
773
|
return callback(null, `Retrieve call for ${entityType} failed.`);
|
|
726
774
|
} catch (e) {
|
|
727
|
-
|
|
775
|
+
log.error(`${origin}: Exception occurred during retrieval - ${e.message}`);
|
|
728
776
|
throw new Error(e);
|
|
729
777
|
}
|
|
730
778
|
}
|
|
@@ -742,68 +790,72 @@ class CacheHandler {
|
|
|
742
790
|
isEntityCached(entityType, entityNames, callback) {
|
|
743
791
|
const origin = `${id}-cacheHandler-isEntityCached`;
|
|
744
792
|
log.trace(origin);
|
|
745
|
-
|
|
793
|
+
|
|
746
794
|
if (!this.enabled) {
|
|
747
|
-
log.
|
|
795
|
+
log.info(`${origin}: Cache is not enabled!`);
|
|
748
796
|
return callback(null, 'Cache is not enabled!');
|
|
749
797
|
}
|
|
750
798
|
|
|
751
|
-
|
|
752
|
-
if (!Array.isArray(entityNames)) {
|
|
753
|
-
names = [entityNames];
|
|
754
|
-
}
|
|
799
|
+
const names = Array.isArray(entityNames) ? entityNames : [entityNames];
|
|
755
800
|
|
|
756
801
|
try {
|
|
802
|
+
log.debug(`${origin}: Checking cache for entityType: ${entityType}, entityNames: ${names}.`);
|
|
803
|
+
|
|
757
804
|
for (let i = 0; i < this.cache.length; i += 1) {
|
|
758
805
|
if (this.cache[i].entityType === entityType) {
|
|
806
|
+
log.info(`${origin}: Cache entry found for entityType: ${entityType}.`);
|
|
807
|
+
|
|
759
808
|
const returnVals = [];
|
|
809
|
+
|
|
810
|
+
// Lock the cache entry to safely access the list
|
|
760
811
|
return lock.acquire(this.cache[i].lockKey, (done) => {
|
|
812
|
+
log.debug(`${origin}: Acquired lock for cache entry of entityType: ${entityType}.`);
|
|
761
813
|
done(this.cache[i].list);
|
|
762
814
|
}, (ret) => {
|
|
763
|
-
// null list means previously flushed or failed called
|
|
764
815
|
if (!ret) {
|
|
765
|
-
log.
|
|
766
|
-
|
|
816
|
+
log.warn(`${origin}: Cache list is null or empty for ${entityType}. Attempting to repopulate.`);
|
|
817
|
+
|
|
818
|
+
return this.populateCache(entityType).then((result) => {
|
|
767
819
|
if (result && result[0] === 'success') {
|
|
768
|
-
|
|
769
|
-
|
|
820
|
+
log.info(`${origin}: Cache repopulation succeeded for ${entityType}. Rechecking cache.`);
|
|
821
|
+
|
|
822
|
+
// Reacquire lock to access the updated cache list
|
|
823
|
+
return lock.acquire(this.cache[i].lockKey, (done) => {
|
|
770
824
|
names.forEach((name) => {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
returnVals.push('found');
|
|
774
|
-
return; // forEach
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
returnVals.push('notfound');
|
|
825
|
+
const isFound = this.cache[i].list.some((item) => item.name === name);
|
|
826
|
+
returnVals.push(isFound ? 'found' : 'notfound');
|
|
778
827
|
});
|
|
779
828
|
done(returnVals);
|
|
780
829
|
}, (retVals) => {
|
|
781
|
-
log.
|
|
830
|
+
log.debug(`${origin}: Final cache check results: ${retVals}`);
|
|
782
831
|
return callback(retVals);
|
|
783
832
|
});
|
|
784
833
|
}
|
|
834
|
+
|
|
835
|
+
log.error(`${origin}: Cache repopulation failed for ${entityType}.`);
|
|
785
836
|
return callback(null, `isEntityCached call for ${entityType} failed.`);
|
|
837
|
+
}).catch((err) => {
|
|
838
|
+
log.error(`${origin}: Error during cache repopulation for ${entityType} - ${err.message}`);
|
|
839
|
+
return callback(null, `isEntityCached call for ${entityType} failed due to repopulation error.`);
|
|
786
840
|
});
|
|
787
841
|
}
|
|
788
842
|
|
|
843
|
+
log.debug(`${origin}: Processing cached list for entityType: ${entityType}.`);
|
|
789
844
|
names.forEach((curName) => {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
returnVals.push('found');
|
|
793
|
-
return; // continue the forEach
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
returnVals.push('notfound');
|
|
845
|
+
const isFound = ret.some((item) => item.name === curName);
|
|
846
|
+
returnVals.push(isFound ? 'found' : 'notfound');
|
|
797
847
|
});
|
|
798
|
-
|
|
848
|
+
|
|
849
|
+
log.debug(`${origin}: Cache check results: ${returnVals}`);
|
|
799
850
|
return callback(returnVals);
|
|
800
851
|
}); // end of lock acquire
|
|
801
852
|
}
|
|
802
853
|
}
|
|
803
|
-
|
|
854
|
+
|
|
855
|
+
log.error(`${origin}: No cache entry found for entityType: ${entityType}.`);
|
|
804
856
|
return callback(false);
|
|
805
857
|
} catch (e) {
|
|
806
|
-
log.error(e);
|
|
858
|
+
log.error(`${origin}: Exception occurred during cache check - ${e.message}`);
|
|
807
859
|
return callback(false);
|
|
808
860
|
}
|
|
809
861
|
}
|
|
@@ -817,14 +869,16 @@ class CacheHandler {
|
|
|
817
869
|
*/
|
|
818
870
|
isEntityTypeToBeCached(entityType, callback) {
|
|
819
871
|
const origin = `${id}-cacheHandler-isEntityTypeToBeCached`;
|
|
820
|
-
log.trace(origin);
|
|
872
|
+
log.trace(`${origin}: Checking if entityType should be cached.`);
|
|
821
873
|
|
|
822
874
|
if (!this.enabled) {
|
|
823
|
-
log.
|
|
875
|
+
log.info(`${origin}: Cache is not enabled.`);
|
|
824
876
|
return callback(null, 'Cache is not enabled!');
|
|
825
877
|
}
|
|
826
878
|
|
|
827
|
-
|
|
879
|
+
const isCached = this.propertiesMap.has(entityType);
|
|
880
|
+
log.debug(`${origin}: entityType "${entityType}" is ${isCached ? '' : 'not '}to be cached.`);
|
|
881
|
+
return callback(isCached);
|
|
828
882
|
}
|
|
829
883
|
|
|
830
884
|
/**
|
|
@@ -836,28 +890,38 @@ class CacheHandler {
|
|
|
836
890
|
*/
|
|
837
891
|
isTaskCached(entityType, task) {
|
|
838
892
|
const origin = `${id}-cacheHandler-isTaskCached`;
|
|
839
|
-
log.trace(origin);
|
|
893
|
+
log.trace(`${origin}: Checking if task "${task}" is cached under entityType "${entityType}".`);
|
|
840
894
|
|
|
841
|
-
//
|
|
842
|
-
if (!this.enabled
|
|
895
|
+
// If cache is disabled or the entityType is not tracked, return false early
|
|
896
|
+
if (!this.enabled) {
|
|
897
|
+
log.info(`${origin}: Cache is not enabled.`);
|
|
843
898
|
return false;
|
|
844
899
|
}
|
|
845
900
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
901
|
+
if (!this.propertiesMap.has(entityType)) {
|
|
902
|
+
log.warn(`${origin}: entityType "${entityType}" is not configured in propertiesMap.`);
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
const cachedEntity = this.props.cache.entities.find(
|
|
907
|
+
(entity) => entity.entityType === entityType
|
|
908
|
+
);
|
|
909
|
+
|
|
910
|
+
if (!cachedEntity) {
|
|
911
|
+
log.error(`${origin}: entityType "${entityType}" not found in cache.`);
|
|
912
|
+
return false;
|
|
858
913
|
}
|
|
859
|
-
|
|
860
|
-
|
|
914
|
+
|
|
915
|
+
const isTaskFound = cachedEntity.cachedTasks.some(
|
|
916
|
+
(cachedTask) => cachedTask.name === task
|
|
917
|
+
);
|
|
918
|
+
|
|
919
|
+
if (isTaskFound) {
|
|
920
|
+
log.debug(`${origin}: Task "${task}" is cached under entityType "${entityType}".`);
|
|
921
|
+
return true;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
log.debug(`${origin}: Task "${task}" is not cached under entityType "${entityType}".`);
|
|
861
925
|
return false;
|
|
862
926
|
}
|
|
863
927
|
}
|