2 задания Quartz, обновляющие одно и то же значение в БД одновременно, вызывают несогласованное поведение

#java #concurrency #quartz-scheduler #race-condition

#java #параллелизм #quartz-планировщик #состояние гонки

Вопрос:

У меня была одна работа quartz, которая выполняла некоторые вещи и занимала много времени для одного конкретного случая, а другие были очень быстрыми. Поэтому я не хочу останавливать свою работу в ожидании, когда один медленный случай выполняется очень долго, а другие вещи завершены. Это задание выполняется и проверяет флаг doStuff. когда doStuff==1, выполните действия и сделайте значение равным 0. Так что при следующем запуске задания оно не должно запускать уже выполненные вещи.

Итак, чтобы решить вышеуказанную проблему, я создал 2 задания. A — быстрое выполнение задания, B — медленное выполнение задания.

У меня есть 2 задания quartz A amp; B, выполняемые одновременно и использующие один флаг, чтобы решить, запускать ли задание и выполнять какие-либо действия или запускать и завершать без каких-либо действий. У меня есть флаг doStuff, и он имеет начальное значение 0. когда это значение равно 1, оба задания должны начать выполнять что-то, и когда они закончат, они должны обновить значение обратно до 0. Когда значение равно 0 и задание запущено, тогда это задание не будет выполнять его. Работа, которую выполняют оба задания A и B, точно такая же, но с разными параметрами. В идеале оба задания должны выполняться, когда флаг равен 1, и выполнять что-то еще, и обновлять значение до 0. Но когда первое задание выполняется и завершается перед запуском второго задания, оно обновляет значение до 0, а при втором запуске считывает значение 0 и ничего не делает.

Флаг doStuff — это столбец DB. Я могу добавить еще один столбец для задания B, но это не очень хороший дизайн, поскольку мы можем получить требование задания C, задания D, и я не могу добавить столбец для каждого требования.

Есть ли лучший способ справиться с этой проблемой?

Примечание: я новичок в Quartz framework.

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

Ниже показано, как выглядит метод выполнения InterruptableJob

 public void execute(JobExecutionContext jobContext) throws JobExecutionException {
    JobDataMap jobDataMap = jobContext.getMergedJobDataMap();
    final long customerId = jobDataMap.getLong(CUSTOMER_ID_KEY);

    List < QAgentAssetSourceInfo > customerAgents = getValuesBasedOnDoStuff();

    // below code is in Runnable run method and will be started in new thread 
    {
        failedAgents.putAll(agentMgmtHelper.get().doStuff(customerAgents, customer.getId(), null, batchSize));


        // we are done with stuff now make value to 0
        unsetDoStuff();
    });

}
 

Комментарии:

1. Добавьте столбец, такой как JOB_NAME , чтобы для каждого задания могла быть строка, а не столбец для каждого задания. Затем сделайте что-то подобное unsetDoStuff([get job name from context]) , которое устанавливает столбец DOSTUFF для конкретной строки, связанной с именем задания.

2. Спасибо, Эндрю, но строк может быть миллионы, и мы что-то делаем с этими строками. Если мы добавим еще одну строку для каждой записи, это удвоит записи.

3. Вы создаете столбец-флаг с n позициями (по одной для каждого задания (A, B, ..)). Для doStuff вас устанавливается значение столбца 111 … и каждое задание проверяет его положение флага и устанавливает значение 0 по завершении. Когда вы получите больше заданий, просто увеличьте столбец.

4. Спасибо, Саша. Что делать, если оба задания принимают значение как 11, а затем одно обновляется как 10, а второе — как 01. Поэтому в следующий раз задание будет либо читать 10, либо 01, зависит от того, какой поток завершится первым. В идеале в следующий раз задание должно считывать значение как 00.