Java指派执行程序由于某种原因失败时,停止执行程序服务


12

我需要某种服务,该服务将在1秒的间隔内同时运行1分钟1分钟。

如果其中一项任务失败,则我想停止该服务,并停止运行该服务的每个任务,并带有某种指示错误的指示器,否则,如果在一分钟后一切正常,则该服务将停止并指示所有指示器均正常运行。

例如,我有2个功能:

Runnable task1 = ()->{
      int num = Math.rand(1,100);
      if (num < 5){
          throw new Exception("something went wrong with this task,terminate");
      }
}

Runnable task2 = ()->{
      int num = Math.rand(1,100)
      return num < 50;
}



ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
task1schedule = scheduledExecutorService.scheduleAtFixedRate(task1, 1, 60, TimeUnit.SECONDS);
task2schedule = scheduledExecutorService.scheduleAtFixedRate(task2, 1, 60, TimeUnit.SECONDS);

if (!task1schedule || !task2schedule) scheduledExecutorService.shutdown();

关于如何解决这个问题并使之尽可能通用的任何想法?


1
除了实际的问题外,几乎没有什么Math.rand不是内置的API。的实现Runnable必须具有void run定义。类型task1/2scheduleScheduledFuture<?>在提供的上下文中。转到实际问题,如何利用它awaitTermination?你可以那样做scheduledExecutorService.awaitTermination(1,TimeUnit.MINUTES);。另外,怎么样检查,如果其中任何一个任务得到了其正常完成前取消:if (task1schedule.isCancelled() || task2schedule.isCancelled()) scheduledExecutorService.shutdown();
纳曼

2
将任务安排为每分钟重复一次是没有意义的,但是然后说,您要停止任务“如果一分钟后一切都顺利”。由于在两种情况下都将停止执行程序,因此安排一分钟后关闭执行程序的任务很简单。期货确实已经表明是否出了问题。您没有说,还想要什么其他类型的指标。
Holger

Answers:


8

这个想法是任务正在推送到公共对象TaskCompleteEvent。如果他们推送错误,调度程序将停止,所有任务将停止。

您可以在“错误”和“成功”映射中检查每个任务迭代的结果。

public class SchedulerTest {

    @Test
    public void scheduler() throws InterruptedException {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        TaskCompleteEvent taskCompleteEvent = new TaskCompleteEvent(scheduledExecutorService);
        Runnable task1 = () -> {
            int num = new Random().nextInt(100);
            if (num < 5) {
                taskCompleteEvent.message("task1-"+UUID.randomUUID().toString(), "Num "+num+" was obatined. Breaking all the executions.", true);
            }
        };
        Runnable task2 = () -> {
            int num = new Random().nextInt(100);
            taskCompleteEvent.message("task2-"+UUID.randomUUID().toString(), num < 50, false);
        };
        scheduledExecutorService.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);
        scheduledExecutorService.scheduleAtFixedRate(task2, 0, 1, TimeUnit.SECONDS);
        scheduledExecutorService.awaitTermination(60, TimeUnit.SECONDS);
        System.out.println("Success: "+taskCompleteEvent.getSuccess());
        System.out.println("Errors: "+taskCompleteEvent.getErrors());
        System.out.println("Went well?: "+taskCompleteEvent.getErrors().isEmpty());
    }

    public static class TaskCompleteEvent {

        private final ScheduledExecutorService scheduledExecutorService;
        private final Map<String, Object> errors = new LinkedHashMap<>();
        private final Map<String, Object> success = new LinkedHashMap<>();

        public TaskCompleteEvent(ScheduledExecutorService scheduledExecutorService) {
            this.scheduledExecutorService = scheduledExecutorService;
        }

        public synchronized void message(String id, Object response, boolean error) {
            if (error) {
                errors.put(id, response);
                scheduledExecutorService.shutdown();
            } else {
                success.put(id, response);
            }
        }

        public synchronized Map<String, Object> getErrors() {
            return errors;
        }

        public synchronized Map<String, Object> getSuccess() {
            return success;
        }

    }

}

2

您只需要添加一个其他任务,该任务的任务是监视所有其他正在运行的任务-并且当任何监视的任务失败时,它们需要设置一个刺客可以检查的信号量(标志)。

    ScheduledExecutorService executor = (ScheduledExecutorService) Executors.newScheduledThreadPool(2);

    // INSTANTIATE THE REMOTE-FILE-MONITOR:
    RemoteFileMonitor monitor = new RemoteFileMonitor(remotesource, localtarget);

    // THIS TimerTask PERIODICALLY TRIGGERS THE RemoteFileMonitor: 
    TimerTask remote = new TimerTask() {

        // RUN FORREST... RUN !
        public void run() {

            try { 

                kae.trace("TimerTask::run() --> Calling RemoteFileMonitor.check()");
                monitor.check();

            } catch (Exception ex) {

                // NULL TRAP: ALLOWS US TO CONTINUE AND RETRY:

            }

        }

    };

    // THIS TimerTask PERIODICALLY TRIES TO KILL THE REMOTE-FILE-MONITOR:
    TimerTask assassin = new TimerTask() {

        // WHERE DO BAD FOLKS GO WHEN THEY DIE ? 
        private final LocalDateTime death = LocalDateTime.now().plus(ConfigurationOptions.getPollingCycleTime(), ChronoUnit.MINUTES);

        // RUN FORREST... RUN !
        public void run() {

            // IS THERE LIFE AFTER DEATH ???
            if (LocalDateTime.now().isAfter(death)) {

                // THEY GO TO A LAKE OF FIRE AND FRY:
                kae.error(ReturnCode.MONITOR_POLLING_CYCLE_EXCEEDED);                   

            }

        }

    };

    // SCHEDULE THE PERIODIC EXECUTION OF THE RemoteFileMonitor: (remote --> run() monitor --> check())
    executor.scheduleAtFixedRate(remote, delay, interval, TimeUnit.MINUTES);

    // SCHEDULE PERIODIC ASSASSINATION ATTEMPTS AGAINST THE RemoteFileMonitor: (assassin --> run() --> after death --> die())
    executor.scheduleAtFixedRate(assassin, delay, 60L, TimeUnit.SECONDS);

    // LOOP UNTIL THE MONITOR COMPLETES:
    do {

        try {

            // I THINK I NEED A NAP:
            Thread.sleep(interval * 10);                

        } catch (InterruptedException e) {

            // FAIL && THEN cleanexit();
            kae.error(ReturnCode.MONITORING_ERROR, "Monitoring of the XXXXXX-Ingestion site was interrupted");

        }

        // NOTE: THE MONITOR IS SET TO 'FINISHED' WHEN THE DONE-File IS DELIVERED AND RETRIEVED:
    } while (monitor.isNotFinished());

    // SHUTDOWN THE MONITOR TASK:
    executor.shutdown();

2
班级TimerTask完全不相关ScheduledExecutorService; 它恰好实现了Runnable。此外,仅检查是否ConfigurationOptions.getPollingCycleTime()已达到特定时间()安排定期任务是没有意义的。您有一个ScheduledExecutorService,因此您可以告诉它在所需的时间安排任务。
Holger

我使用的示例中的实现是,如果某个任务尚未完成,则在一段时间后将其杀死。用例是:如果远程服务器在2小时内未删除文件,请终止该任务。这就是OP的要求。
Greg Patnude

您阅读并理解了我的评论吗?不管代码做什么,它无缘无故地使用不鼓励使用的类,只需替换TimerTaskRunnable,即可解决问题,而无需更改代码的作用。此外,只需使用executor.schedule(assassin, ConfigurationOptions.getPollingCycleTime(), ChronoUnit.MINUTES);它,它将在所需时间运行一次,因此,该if(LocalDateTime.now().isAfter(death))检查已过时。再说一次,除了做起来更简单,更有效之外,它不会改变代码的作用。
Holger
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.