ScheduledExecutorService работает на локальном и тестовом сервере, но запускается только один раз на работающем сервере - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть ScheduledExecutorService, чтобы запланировать выполнение задачи каждые 12 часов в приложении tomcat.Задача вызывает конечную точку REST, выполняет некоторые другие вычисления и возвращает результат.Он отлично работает как локально, так и на тестовом сервере, однако, он работает только один раз и никогда больше на реальном сервереВсе исключения обрабатываются, и задача занимает менее 5 секунд.Я также проверил все свойства на сервере, чтобы убедиться, что свойства времени не переопределяются другими свойствами.Для локального тестирования я сократил время задержки до каждых 10 минут, и это все еще показывает то же поведение, поэтому я исключил время ожидания в качестве проблемы.Я смотрел на другие подобные вопросы, но, похоже, ни один из них не помог с этой проблемой. ScheduledExecutorService запускается только один раз , JAVA ScheduledExecutorService запускается только один раз при вызове Задачи , ScheduledExecutorService только зацикливается только один раз , ScheduledExecutorService - задача останавливается при выполнении , ScheduledExecutorService - игнорировать уже запущенный исполняемый файл , ScheduledExecutorService, проблема с расписанием , Таймер и ScheduledExecutorService планирование

Ниже приведен мой код:

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder({"name", "number"})
public class Company {

    @JsonProperty("name")
    private String name;
    @JsonProperty("number")
    private int number;

    public String getName() {
        return this.name;
    }

    public int getNumber() {
        return this.number;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(Company.class)
            .append("name", this.name)
            .append("number", this.number).toString();
    }
}

public class CompanyDifference {

    private String name;
    private int difference;

    public CompanyDifference(String name, int difference) {
        this.name = name;
        this.difference = difference;
    }

    public String getName() {
        return this.name;
    }

    public int getDifference() {
        return this.difference;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(CompanyDifference.class)
            .append("name", this.name)
            .append("difference", this.difference).toString();
    }
}

@Singleton
public class TaskRunner {
    public void doTask () {
        try {
            System.out.println("takes 2 sets of json data and returns the difference for each company");

            // takes 2 sets of json data and returns the difference for each company
            ObjectMapper mapper = new ObjectMapper();
            InputStream dataOne = Company.class.getResourceAsStream("/data.json");
            InputStream dataTwo = Company.class.getResourceAsStream("/data2.json");

            Company[] companyDataOne = mapper.readValue(dataOne, Company[].class);
            Company[] companyDataTwo = mapper.readValue(dataTwo, Company[].class);

            // Find the difference for each company and map company name to difference
            Map<String, Integer> mapDifferenceToCompany = new HashMap<>();

            for (int i = 0; i < companyDataOne.length; i++) {
                mapDifferenceToCompany.put(companyDataOne[i].getName(), Math.abs(companyDataOne[i].getNumber() - companyDataTwo[i].getNumber()));
            }

            mapDifferenceToCompany.forEach((key, value) -> System.out.println(String.valueOf(new CompanyDifference(key, value))));
        } catch (IOException e) {
            logger.info(String.format("Error: Failed to convert json to object with exception %s", e));
            throw new TaskSchedulerException("Failed to convert json to object with exception", e);
        } catch (Exception e) {
            logger.info(String.format("Error: Failed with exception %s", e));
            throw new TaskSchedulerException("Failed with exception", e);
        }
    }
}

@Singleton
public class TaskScheduler {

    private final Runnable runnable; 
    private final ScheduledExecutorService executorService;
    private static final Logger logger = LoggerFactory.getLogger(TaskScheduler.class);

    @Inject
    public TaskScheduler(TaskRunner taskRunner, int initialDelay, int period, String timeUnits) {
        this.executorService = Executors.newScheduledThreadPool(1);
        this.runnable = taskRunner::doTask;

        this.scheduledFuture = this.executorService.scheduleAtFixedRate(this.runnable, initialDelay, period,    
             TimeUnit.valueOf(timeUnits));
    }

    public static void main(String[] args) {
        TaskRunner taskRunner = new TaskRunner();
        new TaskScheduler(taskRunner, 1, 10, "MINUTES");
    }
}

Задача запускается один раз при запуске после начальной задержки в 1 минуту, но не запускает следующую запланированную задачу.Он пытается запустить запланированное задание, но, похоже, не выполняет задание, и после изучения свойств ScheduledThreadPoolExecutor на работающем сервере я обнаружил, что размер очереди падает до 0 (когда это всегда должно быть 1), что означает, что ни одно задание не было выполнено.по расписанию.

Это говорит о том, что при попытке запустить запланированную задачу после завершения начальной задачи она либо удаляет запланированную задачу, либо не может запланировать следующую задачу, поскольку текущая задача не выполнена.Не выдается никаких ошибок или исключений, так как все исключения были обработаны в методе doTask.Планировщик работает, как и ожидалось, локально и на тестовом сервере, что затрудняет репликацию сценария.

Хотите узнать, отсутствует ли в реализации что-то или что может привести к тому, что она не выполнит следующую запланированную задачу ичто приводит к уменьшению размера очереди до 0. Может ли версия java повлиять на поведение планировщика или есть причины, по которым это может происходить в реальной среде?

Я создал конечную точку REST для мониторингачто происходило под капотом со свойствами ScheduledFuture и ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) schedulerService;
this.queueSize = executor.getQueue().size();
this.remainingCapacity = executor.getQueue().remainingCapacity();
this.terminated = schedulerService.isTerminated();
this.shutdown = schedulerService.isShutdown();
this.taskCount = executor.getTaskCount();
this.activeTaskCount = executor.getActiveCount();
this.completedTaskCount = executor.getCompletedTaskCount();
this.keepAliveTime = executor.getKeepAliveTime(TimeUnit.SECONDS);
this.coreThreadTimeOut = executor.allowsCoreThreadTimeOut();
this.cancelled = scheduledFuture.isCancelled();
this.delay = scheduledFuture.getDelay(TimeUnit.MINUTES);

Результат первого запуска после начальной задержки: из этого мы видим, что он выполнил первое задание, и я получаю требуемый результатиз расчетов.TaskCount (количество запланированных задач с момента запуска) равно 2, что означает, что 2-я задача была запланирована, а размер очереди по-прежнему равен 1. Это нормально.

{
  "queueSize": 1,
  "remainingCapacity": 2147483647,
  "terminated": false,
  "shutdown": false,
  "taskCount": 2,
  "activeTaskCount": 0,
  "completedTaskCount": 1,
  "keepAliveTime": 0,
  "coreThreadTimeOut": false, 
  "periodic": true, 
  "cancelled": false
}

Результат после попытки 2-го запуска: thisэто где он застревает.CompleteTaskCount равен 2, но я не думаю, что он фактически завершает задачу, так как я не получаю результат из расчетов или каких-либо журналов, чтобы показать, что он либо запустил, либо выполнил задачу.TaskCount должен увеличиться до 3, но он застрял в 2, а размер очереди теперь равен 0.

{
  "queueSize": 0,
  "remainingCapacity": 2147483647,
  "terminated": false,
  "shutdown": false,
  "taskCount": 2,
  "activeTaskCount": 0,
  "completedTaskCount": 2,
  "keepAliveTime": 0,
  "coreThreadTimeOut": false, 
  "periodic": true, 
  "cancelled": false
}

Когда я проверяю их на локальном и тестовом сервере, он работает нормально, а taskCount увеличивается какожидается, и размер очереди всегда равен 1, что ожидается.Исходя из этого, я могу сказать, что по какой-то причине задача застревает во 2-м запуске и не завершается, поэтому она не запланирует следующую задачу.

Javadoc говорит: "Если любое выполнениеэтой задачи занимает больше времени, чем ее период, тогда последующие выполнения могут начаться поздно, но не будут выполняться одновременно. " Я предполагаю, что именно поэтому следующая задача не запланирована.Было бы здорово, если бы вы могли объяснить, что может вызвать это

1 Ответ

0 голосов
/ 06 декабря 2018

Проблема не с реализацией, реализация в порядке.После большой отладки у виртуальной машины, на которой работало приложение, возникли проблемы.После многократного перезапуска и повторного развертывания службы приложений, он вернулся в нормальное состояние.Пожалуйста, смотрите вопрос о шагах, предпринятых при отладке приложения.

...