Java dừng dịch vụ thực thi khi một trong những nhiệm vụ được giao của anh ta không thành công vì bất kỳ lý do gì


12

Tôi cần một số loại dịch vụ sẽ chạy một số nhiệm vụ cùng một lúc và trong khoảng thời gian 1 giây trong 1 phút.

Nếu một trong những nhiệm vụ thất bại, tôi muốn dừng dịch vụ và mọi nhiệm vụ chạy với nó với một loại chỉ báo nào đó đã xảy ra sự cố, nếu không, sau một phút mọi thứ sẽ ổn, dịch vụ sẽ dừng lại với một chỉ báo rằng tất cả đều ổn.

Ví dụ, tôi có 2 chức năng:

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();

Bất kỳ ý tưởng về làm thế nào tôi nên giải quyết điều này và làm cho mọi thứ chung chung nhất có thể?


1
Vài điều ngoài câu hỏi thực tế, Math.randkhông phải là API tích hợp. Một thực hiện Runnablephải có một void runđịnh nghĩa. Loại task1/2schedulesẽ ScheduledFuture<?>trong bối cảnh được cung cấp. Chuyển đến câu hỏi thực tế, làm thế nào để đi xung quanh để sử dụng awaitTermination? Bạn có thể làm điều đó như scheduledExecutorService.awaitTermination(1,TimeUnit.MINUTES);. Ngoài ra, về việc kiểm tra xem có bất kỳ tác vụ nào bị hủy trước khi hoàn thành bình thường if (task1schedule.isCancelled() || task2schedule.isCancelled()) scheduledExecutorService.shutdown();không?
Naman

2
Không có ý nghĩa gì trong việc sắp xếp các nhiệm vụ được lặp đi lặp lại mỗi phút, nhưng sau đó nói rằng, bạn muốn dừng các nhiệm vụ, nếu sau một phút mọi thứ đều ổn. Vì bạn đang dừng người thực thi trong cả hai trường hợp, nên việc lên lịch cho một tác vụ tắt trình thực thi sau một phút là chuyện nhỏ. Và tương lai đã chỉ ra liệu có điều gì đó không ổn hay không. Bạn đã không nói, loại chỉ số nào bạn muốn.
Holger

Câu trả lời:


8

Ý tưởng là các tác vụ được đẩy đến một đối tượng chung là TaskCompleteEvent. Nếu họ đẩy một lỗi, bộ lập lịch bị dừng và tất cả các tác vụ sẽ dừng lại.

Bạn có thể kiểm tra kết quả của mỗi lần lặp tác vụ trong "lỗi" và "thành công" trên bản đồ.

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

Bạn chỉ cần thêm một nhiệm vụ bổ sung có nhiệm vụ là giám sát tất cả các nhiệm vụ đang chạy khác - và khi bất kỳ nhiệm vụ được giám sát nào thất bại, họ cần đặt một semaphore (cờ) mà kẻ ám sát có thể kiểm tra.

    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
Lớp học TimerTaskhoàn toàn không liên quan đến ScheduledExecutorService; nó chỉ xảy ra để thực hiện Runnable. Hơn nữa, không có ý nghĩa gì để sắp xếp một nhiệm vụ định kỳ, chỉ để kiểm tra xem ConfigurationOptions.getPollingCycleTime()đã đạt đến một thời gian cụ thể ( ) chưa. Bạn có một ScheduledExecutorService, vì vậy bạn có thể nói với nó để sắp xếp nhiệm vụ đúng thời gian mong muốn.
Holger

Việc thực hiện trong ví dụ tôi đã sử dụng là để giết một tác vụ thực thi sau một khoảng thời gian nhất định nếu tác vụ chưa hoàn thành. Trường hợp sử dụng là: Nếu máy chủ từ xa không đánh rơi tệp trong vòng 2 giờ - giết tác vụ. đây là những gì OP yêu cầu.
Greg Patnude

Bạn đã đọc và hiểu nhận xét của tôi? Nó không có vấn đề gì mã lệnh thực hiện, nó sử dụng một lớp nản không có lý do, chỉ cần thay thế TimerTaskvới Runnablevà bạn đã khắc phục các vấn đề, mà không thay đổi gì mã lệnh thực hiện. Hơn nữa, chỉ cần sử dụng executor.schedule(assassin, ConfigurationOptions.getPollingCycleTime(), ChronoUnit.MINUTES);và nó sẽ chạy một lần tại thời điểm mong muốn, do đó, if(LocalDateTime.now().isAfter(death))kiểm tra đã lỗi thời. Một lần nữa, không thay đổi những gì mã làm, ngoài việc thực hiện nó đơn giản hơn và hiệu quả hơn.
Holger
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.