Caffeineで有効期限にjitterを入れたくなったらExpiryインターフェースを使う

Javaでインメモリでキャッシュしたくなったときによく使うCaffeineだが、エントリの有効期限に jitterを入れたくなることがある。 前やったときどうやったか忘れてしまったので、ここにメモしておく。

インターフェースとしては、Expiryというインターフェースがあり、以下のような形で使う。

        Caffeine.newBuilder()
                .expireAfter(new JitterExpiry<>(Duration.ofSeconds(30)))
                .build();

なお、今回試しで書いてみた実装がこれ。コンストラクタで指定されたdurationをベースに 0.5を係数にjitterを入れる実装になっている。
ちなみに、それぞれのメソッドの戻り値は、nano秒である必要がある。

public class JitterExpiry<K, V> implements Expiry<K, V> {

    private final long duration;

    private final SecureRandom secureRandom = new SecureRandom();

    private JitterExpiry(Duration duration) {
        this.duration = duration.toNanos();
    }


    @Override
    public long expireAfterCreate(K key, V value, long currentTime) {
        return (long) (duration * (2 * secureRandom.nextDouble() - 1));
    }

    @Override
    public long expireAfterUpdate(K key, V value, long currentTime, @NonNegative long currentDuration) {
        return (long) (duration * (2 * secureRandom.nextDouble() - 1));
    }

    @Override
    public long expireAfterRead(K key, V value, long currentTime, @NonNegative long currentDuration) {
        return currentDuration;
    }
}

まだリリースされていないが(ver. 3.1.8現在)、以下の変更でstaticメソッドが追加されているため、これがリリースされた際にはより簡潔に書けるようになるはずだ。

Add Expiry static factory methods (fixes #1499) · ben-manes/caffeine@49df4e9 · GitHub