Я запускаю запланированное задание в своем приложении 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 значение только что полученного.
Есть идеи, как этого можно добиться должным образом?
Боюсь, промывка ничего не изменила. Я также не могу поместить логику паузы в задачу, так как я не смогу запустить ее из любого места.




Насколько я понимаю, вам нужно остановить задание, когда установлен флаг паузы ... вы можете добиться этого, применив оптимистичную блокировку ... добавьте поле @Version в Job .... примените LockModeType.OPTIMISTIC к заданию, которое вы получили в performAction() - либо добавляя его к методу find(), либо вызывая refresh() после извлечения - первый лучше- ..... теперь, если другая конечная точка изменяет флаг паузы, поле версии будет увеличено, и вы получите OptimisticLockException при сохранении .... это имеет некоторые последствия:
1- какое бы состояние ни изменилось в Job, будет происходить то же поведение (не только поле паузы)
2- Вам нужно будет обработать исключение из контекста постоянства (т.е. внутри performActions()), потому что после возврата оно может быть сопоставлено с любым другим типом исключения ... это идея, которая у меня сейчас есть, может быть, есть что-то лучшее, что дает больше контроля (отслеживайте только атрибут pause)
Да, это действительно не идеально, поскольку у действия есть несколько других значений, которые меняются, и было бы неприятно блокировать его при каждом изменении. Я просто хочу быть уверенным, что пауза действительно будет сохраняться.
Я попытаюсь централизовать логику «данных» внутри метода @Transactional, который будет вызываться из запланированной задачи и других. Еще одна вещь, которую следует учитывать, - это кеш JPA, возможно, очистка EntityManager после слияния / сохранения может помочь.