UNPKG

@thermopylae/lib.cache

Version:
85 lines (84 loc) 2.85 kB
import { chrono } from '@thermopylae/lib.utils'; import { EXPIRES_AT_SYM } from "../constants.js"; class IntervalGarbageCollector { options; getNextCacheEntry; iterateTimeoutId; entryExpiredCb; constructor(options) { this.options = IntervalGarbageCollector.fillWithDefaults(options); this.getNextCacheEntry = IntervalGarbageCollector.createCacheEntriesCircularIterator(this.options.iterableBackend); this.iterateTimeoutId = null; } get idle() { return this.iterateTimeoutId == null; } get size() { return this.options.iterableBackend.size; } manage() { if (this.idle) { this.iterateTimeoutId = setTimeout(this.evictExpiredEntries, this.options.checkInterval); } } update() { if (this.idle) { this.iterateTimeoutId = setTimeout(this.evictExpiredEntries, this.options.checkInterval); } } leave() { return undefined; } clear() { clearTimeout(this.iterateTimeoutId); this.iterateTimeoutId = null; } setEntryExpiredCallback(cb) { this.entryExpiredCb = cb; } evictExpiredEntries = () => { const startingEntry = this.getNextCacheEntry(); if (startingEntry == null) { this.iterateTimeoutId = null; return; } let currentEntry = startingEntry; let iteratedEntries = 0; do { if (currentEntry[EXPIRES_AT_SYM] <= chrono.unixTime()) { this.entryExpiredCb(currentEntry); } if (++iteratedEntries < this.options.iterateCount) { currentEntry = this.getNextCacheEntry(); continue; } break; } while (currentEntry != startingEntry && this.options.iterableBackend.size); if (this.options.iterableBackend.size) { this.iterateTimeoutId = setTimeout(this.evictExpiredEntries, this.options.checkInterval); return; } this.iterateTimeoutId = null; }; static fillWithDefaults(options) { options = { ...options }; options.checkInterval = chrono.secondsToMilliseconds(options.checkInterval || 15); options.iterateCount = options.iterateCount || 100; return options; } static createCacheEntriesCircularIterator(backend) { let iterator = backend.values(); return function nextCacheEntry() { let iterResult = iterator.next(); if (iterResult.done) { iterator = backend.values(); iterResult = iterator.next(); if (iterResult.done) { return null; } } return iterResult.value; }; } } export { IntervalGarbageCollector };