private synchronized void process(final Instant now) {
        final DataRetentionRules dataRetentionRules = dataRetentionRulesProvider.get();
        LOGGER.info("All retention time calculations based on now()={}", now);
        if (dataRetentionRules != null) {
            final List<DataRetentionRule> activeRules = getActiveRules(dataRetentionRules.getRules());

            if (activeRules != null && activeRules.size() > 0) {

                // Create a map of unique periods with the set of rules that apply to them.
                final List<ProcessablePeriod> processablePeriods = getProcessPeriods(
                        dataRetentionRules,
                        activeRules,
                        now);

                // Rules must be in ascending order by rule number so they applied in the correct order
                processablePeriods.stream()
                        .sorted(Comparator.comparing(processablePeriod ->
                                // Work backwards in time
                                processablePeriod.timePeriod.getFrom(), Comparator.reverseOrder()))
                        .takeWhile(entry -> {
                            if (Thread.currentThread().isInterrupted()) {
                                LOGGER.error("Thread interrupted");
                                throw new TaskTerminatedException();
                            } else {
                                return true;
                            }
                        })
                        .forEach(processablePeriod -> {
                            final List<DataRetentionRuleAction> ruleActions =
                                    processablePeriod.dataRetentionRuleActions;
                            final TimePeriod period = processablePeriod.timePeriod;

                            final List<DataRetentionRuleAction> sortedActions = ruleActions.stream()
                                    .sorted(DataRetentionRuleAction.comparingByRuleNo())
                                    .collect(Collectors.toList());

                            processPeriod(period, sortedActions, processablePeriod.ruleAge, now);

                            // We have successfully processed this period so update the tracker
                            // so the next run on this period can work from where we got to
                            final DataRetentionTracker newTracker = new DataRetentionTracker(
                                    dataRetentionRules.getVersion(),
                                    processablePeriod.ruleAge,
                                    now);
                            metaService.setTracker(newTracker);
                        });
            } else {
                LOGGER.info("No active rules to process");
            }
        } else {
            LOGGER.info("No active rules to process");
        }
    }
Pkg private so we can test with a known now time
stroom-data/stroom-data-retention-impl/src/main/java/stroom/data/retention/impl/DataRetentionPolicyExecutor.java