Spring JPA: изменение атрибута экземпляра, который одновременно изменяется в запланированной задаче

Я запускаю запланированное задание в своем приложении Spring, которое выполняет задание. Само задание извлекается в начале задания. После этого выполняется цикл, изменяющий задание на каждой итерации (++ счетчик). После цикла я объединяю свой экземпляр с помощью диспетчера сущностей. Он работает довольно хорошо, но я столкнулся с проблемой, пытаясь изменить экземпляр из другого места. Поскольку у экземпляра есть флаг «приостановлено», я пытаюсь его установить. Но всякий раз, когда я это делаю, он снова быстро сбрасывается из-за запланированной задачи, снова сбрасывающей его (насколько я могу судить).

Вот код:

// This method is called using the @Scheduled annotation to be looping
// constantly with one second delay between invocations.
@Transactional
public void performActions() {
    Job job = jobRepository.findFirstByPausedAtIsNull();
    // Skip if no unpaused job exists
    if (job == null) return;
    // Iterate through batch of job actions
    for(Action action : job.nextActions()) {
        action.perform();
        job.increaseActionsPerformedCount();
        // Merge the action into the persistence context
        entityManager.merge(action);
    }
    // Merge the job into the persistence context
    entityManager.merge(job);
}

Теперь я пытаюсь в любой момент приостановить работу извне. Я использую конечную точку контроллера для вызова метода паузы в jobService. Этот метод выглядит так:

public Job pause(long id) throws JobNotFoundException, JobStatusException {
    Job job = this.show(id);
    if (job.getPausedAt() != null) throw new JobStatusException("The job is already paused");
    job.pause(); // This sets the flag on the instance, same as job.setPausedAt(new Date())
    return jobRepository.save(campaign); // Uses CrudRepository
}

Теперь вызов метода работает нормально и фактически возвращает задание с установленным pausedAt. Но после этого значение быстро сбрасывается.

Я попытался просто получить новый экземпляр из базы данных в конце performAction и установить для измененного экземпляра pausedAt значение только что полученного.

Есть идеи, как этого можно добиться должным образом?

Я попытаюсь централизовать логику «данных» внутри метода @Transactional, который будет вызываться из запланированной задачи и других. Еще одна вещь, которую следует учитывать, - это кеш JPA, возможно, очистка EntityManager после слияния / сохранения может помочь.

spekdrum 14.03.2018 13:10

Боюсь, промывка ничего не изменила. Я также не могу поместить логику паузы в задачу, так как я не смогу запустить ее из любого места.

brfrth 15.03.2018 17:54
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
52
1

Ответы 1

Насколько я понимаю, вам нужно остановить задание, когда установлен флаг паузы ... вы можете добиться этого, применив оптимистичную блокировку ... добавьте поле @Version в Job .... примените LockModeType.OPTIMISTIC к заданию, которое вы получили в performAction() - либо добавляя его к методу find(), либо вызывая refresh() после извлечения - первый лучше- ..... теперь, если другая конечная точка изменяет флаг паузы, поле версии будет увеличено, и вы получите OptimisticLockException при сохранении .... это имеет некоторые последствия:

1- какое бы состояние ни изменилось в Job, будет происходить то же поведение (не только поле паузы)

2- Вам нужно будет обработать исключение из контекста постоянства (т.е. внутри performActions()), потому что после возврата оно может быть сопоставлено с любым другим типом исключения ... это идея, которая у меня сейчас есть, может быть, есть что-то лучшее, что дает больше контроля (отслеживайте только атрибут pause)

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

brfrth 15.03.2018 17:54

Другие вопросы по теме