Skip to content

Issues with Scheduler #49

@aiguofer

Description

@aiguofer

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:

Image

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions