class CTSReaper implements Runnable {

    public void run() {

        debug("Reaper starting");

        // Timers for debugging
        StopWatch query = new StopWatch();
        StopWatch waiting = new StopWatch();

        // Latches will track deletion of each page of results
        List<CountDownLatch> latches = new ArrayList<CountDownLatch>();

        try (ReaperQuery reaperQuery = queryFactory.getQuery()) {
            long total = 0;
            query.start();
            for (Collection<String> ids = reaperQuery.nextPage(); ids != null; ids = reaperQuery.nextPage()) {
                // If the thread has been interrupted, exit all processing.
                if (Thread.interrupted()) {
                    Thread.currentThread().interrupt();
                    debug("Interrupted, returning");
                    return;
                }

                total += ids.size();
                debug("Queried {0} tokens", Long.toString(total));

                // Latch will track the deletions of the page
                latches.add(tokenDeletion.deleteBatch(ids));
            }

            query.stop();
            waiting.start();

            debug("Expired Token Query Time: {0}ms", Long.toString(query.getTime()));

            // Wait stage
            for (CountDownLatch latch : latches) {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }

            waiting.stop();
            monitoringStore.addReaperRun(query.getStartTime(), query.getTime() + waiting.getTime(), total);

            debug("Worker threads Time: {0}ms", Long.toString(waiting.getTime()));
        } catch (CoreTokenException | IOException e) {
            debug.error("CTS Reaper failed", e);
        }

        debug("Reaper complete");
    }

    @Inject public  CTSReaper(final ReaperQueryFactory queryFactory, final TokenDeletion tokenDeletion,
                     final CTSReaperMonitoringStore monitoringStore,
                     @Named(CoreTokenConstants.CTS_REAPER_DEBUG) final Debug debug);

}