@itentialopensource/adapter-utils 5.10.5 → 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 +247 -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,74 +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);
|
|
518
|
+
} else {
|
|
519
|
+
log.debug(`${origin}: Cache remains disabled. No action required.`);
|
|
488
520
|
}
|
|
489
|
-
log.warn('Cache was disabled from enabled, removed cache memory.');
|
|
490
521
|
return;
|
|
491
522
|
}
|
|
492
523
|
|
|
493
|
-
|
|
524
|
+
log.debug(`${origin}: Checking for deleted or updated entity types.`);
|
|
494
525
|
this.propertiesMap.forEach((value, key) => {
|
|
526
|
+
let entityExists = false;
|
|
527
|
+
|
|
495
528
|
for (let i = 0; i < this.props.cache.entities.length; i += 1) {
|
|
496
|
-
if (
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
log.warn(`${origin}: Removed cache entity type due to change in properties.`);
|
|
500
|
-
log.info(`Deleted props for entity type ${key} with val ${value}`);
|
|
501
|
-
return; // continue forEach
|
|
529
|
+
if (this.props.cache.entities[i].name === key) {
|
|
530
|
+
entityExists = true;
|
|
531
|
+
break;
|
|
502
532
|
}
|
|
503
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
|
+
}
|
|
504
541
|
});
|
|
505
542
|
|
|
506
|
-
|
|
543
|
+
log.debug(`${origin}: Updating and setting properties map for cache entities.`);
|
|
507
544
|
this.props.cache.entities.forEach((entity) => {
|
|
508
545
|
if (!this.propertiesMap.has(entity.entityType)) {
|
|
509
|
-
|
|
546
|
+
log.debug(`${origin}: Adding new entity type '${entity.entityType}' to properties map.`);
|
|
510
547
|
this.propertiesMap.set(entity.entityType, {});
|
|
511
|
-
this.propertiesMap.get(entity.entityType)
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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;
|
|
516
554
|
|
|
517
555
|
const newIntervalId = setInterval(() => {
|
|
556
|
+
log.debug(`${origin}: Populating cache for entity type '${entity.entityType}'.`);
|
|
518
557
|
this.populateCache(entity.entityType);
|
|
519
558
|
}, entity.frequency * 60000);
|
|
520
559
|
|
|
521
560
|
const sort = Object.prototype.hasOwnProperty.call(entity, 'sort') ? entity.sort : true; // default true
|
|
522
561
|
this.cache.push(createCacheEntity(entity.entityType, null, newIntervalId, sort));
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
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
|
+
});
|
|
537
580
|
} else {
|
|
538
|
-
|
|
539
|
-
|
|
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}'.`);
|
|
540
586
|
changeUpdateFrequency(this.cache, entity.entityType, entity.frequency, this);
|
|
541
587
|
}
|
|
542
588
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
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;
|
|
548
594
|
}
|
|
549
595
|
});
|
|
550
596
|
}
|
|
@@ -561,37 +607,37 @@ class CacheHandler {
|
|
|
561
607
|
log.trace(origin);
|
|
562
608
|
|
|
563
609
|
if (!this.enabled) {
|
|
610
|
+
log.info(`${origin}: Cache is not enabled. Populate operation aborted.`);
|
|
564
611
|
return Promise.reject(new Error('Cache is not enabled!'));
|
|
565
612
|
}
|
|
566
613
|
|
|
567
|
-
log.info(
|
|
614
|
+
log.info(`${origin}: Starting cache population.`);
|
|
568
615
|
|
|
569
|
-
//
|
|
616
|
+
// Support string and array input
|
|
570
617
|
let entityArr = entities;
|
|
571
618
|
if (!Array.isArray(entities)) {
|
|
572
619
|
entityArr = [entities];
|
|
573
620
|
}
|
|
574
621
|
|
|
575
|
-
//
|
|
622
|
+
// Ensure all entities are tracked
|
|
576
623
|
for (let i = 0; i < entityArr.length; i += 1) {
|
|
577
624
|
const entityType = entityArr[i];
|
|
578
625
|
if (!this.propertiesMap.has(entityType)) {
|
|
579
|
-
log.error(`${entityType} is an untracked entity type! Check properties.`);
|
|
626
|
+
log.error(`${origin}: ${entityType} is an untracked entity type! Check properties.`);
|
|
580
627
|
return Promise.reject(new Error(`${entityType} is an untracked entity type! Check properties.`));
|
|
581
628
|
}
|
|
582
629
|
}
|
|
583
630
|
|
|
584
631
|
try {
|
|
585
632
|
const promiseArr = [];
|
|
586
|
-
//
|
|
633
|
+
// Populate each entity type
|
|
587
634
|
for (let j = 0; j < entityArr.length; j += 1) {
|
|
588
635
|
const entityType = entityArr[j];
|
|
589
|
-
// try to find current entityType in cache
|
|
590
636
|
for (let i = 0; i < this.cache.length; i += 1) {
|
|
591
|
-
if (this.cache[i].entityType === entityType) {
|
|
637
|
+
if (this.cache[i].entityType === entityType) {
|
|
592
638
|
promiseArr.push(new Promise((resolve, reject) => {
|
|
593
639
|
makeIAPCall(this.propertiesMap.get(entityType).populate, this.requestHandler, (cacheData, error) => {
|
|
594
|
-
//
|
|
640
|
+
// Error handling
|
|
595
641
|
let errorMsg = null;
|
|
596
642
|
if (error) {
|
|
597
643
|
errorMsg = `${origin}: ${entityType} failed with error ${error.IAPerror.displayString}.`;
|
|
@@ -600,17 +646,12 @@ class CacheHandler {
|
|
|
600
646
|
} else if (cacheData.length === 0) {
|
|
601
647
|
errorMsg = `${origin}: ${entityType} failed. Nothing found.`;
|
|
602
648
|
}
|
|
603
|
-
// handle error
|
|
604
|
-
if (errorMsg !== null) {
|
|
605
|
-
/**
|
|
606
|
-
* removed unnecessary check if cache[i].list is null here
|
|
607
|
-
* setting null var to null again is fine and shortens critical section
|
|
608
|
-
* */
|
|
609
649
|
|
|
650
|
+
if (errorMsg !== null) {
|
|
610
651
|
if (this.propertiesMap.get(entityType).flushOnFail) {
|
|
611
652
|
lock.acquire(this.cache[i].lockKey, (done) => {
|
|
612
653
|
this.cache[i].list = null;
|
|
613
|
-
done(`${errorMsg}
|
|
654
|
+
done(`${errorMsg} Cache flushed.`);
|
|
614
655
|
}, (ret) => {
|
|
615
656
|
log.error(ret);
|
|
616
657
|
});
|
|
@@ -618,24 +659,22 @@ class CacheHandler {
|
|
|
618
659
|
log.error(`${errorMsg} Keeping old data.`);
|
|
619
660
|
}
|
|
620
661
|
|
|
621
|
-
// bad path
|
|
622
662
|
if (error && error.icode === 'AD.301') {
|
|
623
663
|
return reject(error);
|
|
624
664
|
}
|
|
625
665
|
return resolve('error');
|
|
626
666
|
}
|
|
627
|
-
|
|
667
|
+
|
|
668
|
+
// Sort and update cache
|
|
628
669
|
if (this.cache[i].sort) {
|
|
629
670
|
cacheData.sort(compareByName);
|
|
630
671
|
}
|
|
631
|
-
|
|
632
|
-
// no error, edit cache
|
|
633
672
|
lock.acquire(this.cache[i].lockKey, (done) => {
|
|
634
|
-
if (this.enabled) {
|
|
673
|
+
if (this.enabled) {
|
|
635
674
|
this.cache[i].list = cacheData;
|
|
636
|
-
done(`${
|
|
675
|
+
done(`${origin}: ${entityType} cache updated successfully.`);
|
|
637
676
|
} else {
|
|
638
|
-
done(
|
|
677
|
+
done(`${origin}: Populate cancelled due to disabled cache.`);
|
|
639
678
|
}
|
|
640
679
|
}, (ret) => {
|
|
641
680
|
log.info(ret);
|
|
@@ -647,6 +686,8 @@ class CacheHandler {
|
|
|
647
686
|
}
|
|
648
687
|
}
|
|
649
688
|
}
|
|
689
|
+
|
|
690
|
+
// Resolve all promises
|
|
650
691
|
const arr = await Promise.allSettled(promiseArr);
|
|
651
692
|
return new Promise((resolve, reject) => {
|
|
652
693
|
const valueArray = [];
|
|
@@ -659,7 +700,7 @@ class CacheHandler {
|
|
|
659
700
|
resolve(valueArray);
|
|
660
701
|
});
|
|
661
702
|
} catch (e) {
|
|
662
|
-
|
|
703
|
+
log.error(`${origin}: An exception occurred during cache population - ${e.message}`);
|
|
663
704
|
throw new Error(e);
|
|
664
705
|
}
|
|
665
706
|
}
|
|
@@ -682,47 +723,56 @@ class CacheHandler {
|
|
|
682
723
|
log.trace(origin);
|
|
683
724
|
|
|
684
725
|
if (!this.enabled) {
|
|
685
|
-
log.
|
|
726
|
+
log.info(`${origin}: Cache is not enabled!`);
|
|
686
727
|
return callback(null, 'Cache is not enabled.');
|
|
687
728
|
}
|
|
688
729
|
|
|
689
730
|
if (typeof entityType !== 'string') {
|
|
690
|
-
log.error(`${entityType} is not of type String
|
|
731
|
+
log.error(`${origin}: Invalid entityType - ${entityType} is not of type String.`);
|
|
691
732
|
return callback(null, `${entityType} is not of type String`);
|
|
692
733
|
}
|
|
693
734
|
|
|
694
735
|
try {
|
|
695
736
|
const options = validateOptions(opts); // may throw error
|
|
696
|
-
|
|
737
|
+
|
|
738
|
+
log.debug(`${origin}: Searching cache for entityType: ${entityType}.`);
|
|
739
|
+
// Search for the specified entityType in the cache
|
|
697
740
|
for (let i = 0; i < this.cache.length; i += 1) {
|
|
698
|
-
// check if entity type we care about
|
|
699
741
|
if (this.cache[i].entityType === entityType) {
|
|
700
|
-
|
|
701
|
-
|
|
742
|
+
log.info(`${origin}: Found cache entry for entityType: ${entityType}.`);
|
|
743
|
+
|
|
744
|
+
// Lock the cache entry for safe access
|
|
702
745
|
return lock.acquire(this.cache[i].lockKey, (done) => {
|
|
703
|
-
|
|
746
|
+
log.debug(`${origin}: Retrieved cache list for entityType: ${entityType}.`);
|
|
704
747
|
done(this.cache[i].list);
|
|
705
748
|
}, (ret) => {
|
|
706
|
-
// last iap call failed and flushed, attempt new iap call
|
|
707
749
|
if (!ret) {
|
|
708
|
-
|
|
750
|
+
log.warn(`${origin}: Last IAP call failed and flushed cache for ${entityType}. Attempting to repopulate.`);
|
|
751
|
+
|
|
752
|
+
// Repopulate cache and retry retrieval
|
|
709
753
|
return this.populateCache(entityType).then((result) => {
|
|
710
754
|
if (result && result[0] === 'success') {
|
|
755
|
+
log.info(`${origin}: Repopulation succeeded for ${entityType}. Retrieving updated entries.`);
|
|
711
756
|
return retrieveCacheEntriesHelper(this.cache, entityType, options, callback);
|
|
712
757
|
}
|
|
713
|
-
|
|
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.`);
|
|
714
763
|
});
|
|
715
764
|
}
|
|
716
765
|
|
|
717
|
-
|
|
766
|
+
log.debug(`${origin}: Retrieved entries successfully for entityType: ${entityType}.`);
|
|
718
767
|
return retrieveCacheEntriesHelper(this.cache, entityType, options, callback);
|
|
719
768
|
});
|
|
720
769
|
}
|
|
721
770
|
}
|
|
722
|
-
|
|
771
|
+
|
|
772
|
+
log.error(`${origin}: Cache entry not found for entityType: ${entityType}.`);
|
|
723
773
|
return callback(null, `Retrieve call for ${entityType} failed.`);
|
|
724
774
|
} catch (e) {
|
|
725
|
-
|
|
775
|
+
log.error(`${origin}: Exception occurred during retrieval - ${e.message}`);
|
|
726
776
|
throw new Error(e);
|
|
727
777
|
}
|
|
728
778
|
}
|
|
@@ -740,68 +790,72 @@ class CacheHandler {
|
|
|
740
790
|
isEntityCached(entityType, entityNames, callback) {
|
|
741
791
|
const origin = `${id}-cacheHandler-isEntityCached`;
|
|
742
792
|
log.trace(origin);
|
|
743
|
-
|
|
793
|
+
|
|
744
794
|
if (!this.enabled) {
|
|
745
|
-
log.
|
|
795
|
+
log.info(`${origin}: Cache is not enabled!`);
|
|
746
796
|
return callback(null, 'Cache is not enabled!');
|
|
747
797
|
}
|
|
748
798
|
|
|
749
|
-
|
|
750
|
-
if (!Array.isArray(entityNames)) {
|
|
751
|
-
names = [entityNames];
|
|
752
|
-
}
|
|
799
|
+
const names = Array.isArray(entityNames) ? entityNames : [entityNames];
|
|
753
800
|
|
|
754
801
|
try {
|
|
802
|
+
log.debug(`${origin}: Checking cache for entityType: ${entityType}, entityNames: ${names}.`);
|
|
803
|
+
|
|
755
804
|
for (let i = 0; i < this.cache.length; i += 1) {
|
|
756
805
|
if (this.cache[i].entityType === entityType) {
|
|
806
|
+
log.info(`${origin}: Cache entry found for entityType: ${entityType}.`);
|
|
807
|
+
|
|
757
808
|
const returnVals = [];
|
|
809
|
+
|
|
810
|
+
// Lock the cache entry to safely access the list
|
|
758
811
|
return lock.acquire(this.cache[i].lockKey, (done) => {
|
|
812
|
+
log.debug(`${origin}: Acquired lock for cache entry of entityType: ${entityType}.`);
|
|
759
813
|
done(this.cache[i].list);
|
|
760
814
|
}, (ret) => {
|
|
761
|
-
// null list means previously flushed or failed called
|
|
762
815
|
if (!ret) {
|
|
763
|
-
log.
|
|
764
|
-
|
|
816
|
+
log.warn(`${origin}: Cache list is null or empty for ${entityType}. Attempting to repopulate.`);
|
|
817
|
+
|
|
818
|
+
return this.populateCache(entityType).then((result) => {
|
|
765
819
|
if (result && result[0] === 'success') {
|
|
766
|
-
|
|
767
|
-
|
|
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) => {
|
|
768
824
|
names.forEach((name) => {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
returnVals.push('found');
|
|
772
|
-
return; // forEach
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
returnVals.push('notfound');
|
|
825
|
+
const isFound = this.cache[i].list.some((item) => item.name === name);
|
|
826
|
+
returnVals.push(isFound ? 'found' : 'notfound');
|
|
776
827
|
});
|
|
777
828
|
done(returnVals);
|
|
778
829
|
}, (retVals) => {
|
|
779
|
-
log.
|
|
830
|
+
log.debug(`${origin}: Final cache check results: ${retVals}`);
|
|
780
831
|
return callback(retVals);
|
|
781
832
|
});
|
|
782
833
|
}
|
|
834
|
+
|
|
835
|
+
log.error(`${origin}: Cache repopulation failed for ${entityType}.`);
|
|
783
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.`);
|
|
784
840
|
});
|
|
785
841
|
}
|
|
786
842
|
|
|
843
|
+
log.debug(`${origin}: Processing cached list for entityType: ${entityType}.`);
|
|
787
844
|
names.forEach((curName) => {
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
returnVals.push('found');
|
|
791
|
-
return; // continue the forEach
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
returnVals.push('notfound');
|
|
845
|
+
const isFound = ret.some((item) => item.name === curName);
|
|
846
|
+
returnVals.push(isFound ? 'found' : 'notfound');
|
|
795
847
|
});
|
|
796
|
-
|
|
848
|
+
|
|
849
|
+
log.debug(`${origin}: Cache check results: ${returnVals}`);
|
|
797
850
|
return callback(returnVals);
|
|
798
851
|
}); // end of lock acquire
|
|
799
852
|
}
|
|
800
853
|
}
|
|
801
|
-
|
|
854
|
+
|
|
855
|
+
log.error(`${origin}: No cache entry found for entityType: ${entityType}.`);
|
|
802
856
|
return callback(false);
|
|
803
857
|
} catch (e) {
|
|
804
|
-
log.error(e);
|
|
858
|
+
log.error(`${origin}: Exception occurred during cache check - ${e.message}`);
|
|
805
859
|
return callback(false);
|
|
806
860
|
}
|
|
807
861
|
}
|
|
@@ -815,14 +869,16 @@ class CacheHandler {
|
|
|
815
869
|
*/
|
|
816
870
|
isEntityTypeToBeCached(entityType, callback) {
|
|
817
871
|
const origin = `${id}-cacheHandler-isEntityTypeToBeCached`;
|
|
818
|
-
log.trace(origin);
|
|
872
|
+
log.trace(`${origin}: Checking if entityType should be cached.`);
|
|
819
873
|
|
|
820
874
|
if (!this.enabled) {
|
|
821
|
-
log.
|
|
875
|
+
log.info(`${origin}: Cache is not enabled.`);
|
|
822
876
|
return callback(null, 'Cache is not enabled!');
|
|
823
877
|
}
|
|
824
878
|
|
|
825
|
-
|
|
879
|
+
const isCached = this.propertiesMap.has(entityType);
|
|
880
|
+
log.debug(`${origin}: entityType "${entityType}" is ${isCached ? '' : 'not '}to be cached.`);
|
|
881
|
+
return callback(isCached);
|
|
826
882
|
}
|
|
827
883
|
|
|
828
884
|
/**
|
|
@@ -834,28 +890,38 @@ class CacheHandler {
|
|
|
834
890
|
*/
|
|
835
891
|
isTaskCached(entityType, task) {
|
|
836
892
|
const origin = `${id}-cacheHandler-isTaskCached`;
|
|
837
|
-
log.trace(origin);
|
|
893
|
+
log.trace(`${origin}: Checking if task "${task}" is cached under entityType "${entityType}".`);
|
|
838
894
|
|
|
839
|
-
//
|
|
840
|
-
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.`);
|
|
841
898
|
return false;
|
|
842
899
|
}
|
|
843
900
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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;
|
|
856
913
|
}
|
|
857
|
-
|
|
858
|
-
|
|
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}".`);
|
|
859
925
|
return false;
|
|
860
926
|
}
|
|
861
927
|
}
|