-
Notifications
You must be signed in to change notification settings - Fork 19
Description
I've been debugging an issue where stale cache entries aren't getting evicted in low usage environments even when using a scheduler. After some debugging, I believe it's due to how Node.getAccessTime() gets calculated. I'm not exactly sure if the issue only happens when using aedile or whether it's also present in caffeine.
In order to debug, I created my own scheduler which logs out when a task is scheduled and adds a breakpoint to see where this gets called. Going through the debugger, I noticed sometimes the next scheduled event is FAAAR in the future because now - node.getAccessTime() sometimes returns a negative number in BoundedLocalCache.getExpirationDelay, so delay = Math.min(delay, expiresAfterAccessNanos() - (now - node.getAccessTime())); ends up bing very large.
Here's some logs from my scheduler:
For reference, here's my cache definition:
fun <T> createDataSourceCache(): Cache<DataSourceId, T> where T : Closeable, T : DataSource {
return Caffeine.newBuilder()
.expireAfterAccess(1.toDuration(DurationUnit.MINUTES))
.scheduler(CustomCaffeineScheduler())
.removalListener { key: DataSourceId?, value: T?, cause: RemovalCause ->
logger.info { "Removing key='$key' from DataSource cache due to $cause" }
try {
value!!.close()
} catch (e: Exception) {
logger.error(e) { "Error removing data source from cache for key='$key'" }
}
}
.asCache()
}
class CustomCaffeineScheduler : Scheduler {
private val scheduler = Executors.newSingleThreadScheduledExecutor()
override fun schedule(
executor: Executor,
command: Runnable,
delay: Long,
unit: TimeUnit,
): Future<*> {
logger.info { "Scheduling $command with $delay $unit delay" }
return scheduler.schedule({ executor.execute(command) }, delay, unit)
}
// Remember to shut down the scheduler when no longer needed
fun shutdown() {
scheduler.shutdown()
}
}
Let me know if there's any other information I can provide!