【问题标题】:Run a function (e.g. cleanup) only a single time after multiple POSTs/DELETEs/PUTs在多次 POST/DELETE/PUT 后仅运行一次功能(例如清理)
【发布时间】:2019-05-02 17:25:39
【问题描述】:

我的网站上的流量可能会变得很重,我想放慢运行昂贵的清理功能的频率;我也想在后台运行它。

我使用removingListener 实现了一个缓存,并希望它在创建条目后30 秒异步运行,但我发现它要么根本不运行,要么立即运行。当它运行时,我还必须等待清理脚本。我是否误解了缓存和删除侦听器的目的?

@Path("my-endpoint")
public class MyResource{

    private static final Cache<String, String> debounceCleaner = CacheBuilder
        .newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(30, TimeUnit.SECONDS)
        .removalListener((RemovalListener<String, String>) x-> new Cleaner().clean())
        .build();

    @PUT
    public Response update(){
        ...

        try{
            debounceCleaner.get("foo", ()->"bar");
        } catch (ExecutionException ex){
            throw new IllegalStateException("Unhandled", ex);
        }

        return Response(...)

【问题讨论】:

  • 你在哪里设置缓存?
  • debounceCleaner 是缓存。我发现了一个可能使我重复的问题——我会相应地更新stackoverflow.com/questions/10626720/…
  • Guava 不使用调度线程来处理过期,而是等待它过期并发生其他访问。当有足够的工作堆积时,它会触发维护周期并发送通知。您当然可以使用ScheduledExecutorService 自行安排。
  • 谢谢,本。我注意到它在下一次访问时触发,这不是我想要的。我还尝试了您的 Caffeine 包(性能更好),但我违反了编码的基本规则——将包用于不打算用于的东西。

标签: java guava debounce


【解决方案1】:

缓存过期不打算用作去抖动器。其他问题已经在不同程度上回答了如何创建去抖动器。

implementing debounce in Java Deliver the first item immediately, 'debounce' following items

我为这个应用写了一个去抖动器如下:

public class Debouncer {

    private final int TIMEOUT = 30000;
    private Runnable runnable;
    private Thread backgroundRunnerLoop;
    private Date lastRun = null;
    private Date lastRequest = null;

    public Debouncer(Runnable runnable) {
        this.runnable = runnable;
        this.backgroundRunnerLoop = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(TIMEOUT);
                    if (lastRequest != null && (lastRun == null || lastRun.before(DateUtils.addMilliseconds(lastRequest, TIMEOUT)))) {
                        this.runnable.run();
                        lastRun = new Date();
                    }
                } catch (Exception ex) {
                    throw new IllegalStateException("Debouncer loop broke.", ex);
                }
            }
        });
    }

    public void start() {
        if(!backgroundRunnerLoop.isAlive()){
            backgroundRunnerLoop.start();
        }
    }

    public void resetTimer() {
        lastRequest = new Date();
    }
}

我这样实例化它

@Path("my-endpoint")
public class MyResource {
    private static final Debouncer debouncer = new Debouncer(() -> new Cleaner().run());

    public MyResource() {
        debouncer.start();
    }

    @PUT
    public Response update(){
        // ...
        debouncer.resetTimer();

        return Response.noContent(...).build();
    }
}

【讨论】:

  • 在开始循环之前,您可能需要将 setDaemon(true) 添加到线程:
猜你喜欢
  • 2018-01-14
  • 1970-01-01
  • 2019-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-14
相关资源
最近更新 更多