Java หยุดบริการผู้ปฏิบัติการเมื่องานที่ได้รับมอบหมายอย่างใดอย่างหนึ่งของเขาล้มเหลวด้วยเหตุผลใด


12

ฉันต้องการบริการบางประเภทที่จะทำงานสองสามอย่างพร้อมกันและในช่วงเวลา 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/2scheduleจะอยู่ScheduledFuture<?>ในบริบทที่ให้ไว้ การย้ายไปยังคำถามจริงจะนำไปใช้ให้เกิดประโยชน์ได้awaitTerminationอย่างไร คุณสามารถทำเช่นscheduledExecutorService.awaitTermination(1,TimeUnit.MINUTES);นั้นได้ อีกวิธีหนึ่งคือการตรวจสอบว่างานใด ๆ ที่ถูกยกเลิกก่อนที่จะเสร็จสมบูรณ์ตามปกติ: if (task1schedule.isCancelled() || task2schedule.isCancelled()) scheduledExecutorService.shutdown();?
Naman

2
ไม่มีความหมายในการกำหนดเวลางานที่จะทำซ้ำทุกนาที แต่จากนั้นพูดว่าคุณต้องการหยุดงาน "ถ้าหลังจากผ่านไปหนึ่งนาทีทุกอย่างก็ดี" เนื่องจากคุณกำลังหยุดตัวเรียกใช้งานไม่ว่าในกรณีใดกรณีหนึ่งการจัดกำหนดการงานที่จะปิดตัวเรียกใช้งานหลังจากหนึ่งนาทีนั้นไม่สำคัญ และอนาคตก็บ่งบอกว่ามีบางอย่างผิดปกติหรือไม่ คุณไม่ได้พูดว่าคุณต้องการตัวบ่งชี้ประเภทใด
Holger

คำตอบ:


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

คุณอ่านและเข้าใจความคิดเห็นของฉันหรือยัง? มันไม่สำคัญว่ารหัสทำอะไร แต่ใช้คลาสที่หมดกำลังใจโดยไม่มีเหตุผลเพียงแค่แทนที่TimerTaskด้วยRunnableและคุณได้แก้ไขปัญหาโดยไม่เปลี่ยนสิ่งที่โค้ดทำ เพิ่มเติมเพียงแค่ใช้executor.schedule(assassin, ConfigurationOptions.getPollingCycleTime(), ChronoUnit.MINUTES);และมันจะทำงานครั้งเดียวในเวลาที่ต้องการดังนั้นการif(LocalDateTime.now().isAfter(death))ตรวจสอบจะล้าสมัย อีกครั้งสิ่งที่ไม่เปลี่ยนสิ่งที่รหัสทำนอกเหนือจากการทำมันง่ายขึ้นอย่างมีนัยสำคัญและมีประสิทธิภาพมากขึ้น
Holger
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.