В моем приложении при создании задачи мне нужно вызвать API для Google, чтобы создать событие календаря Google.
Я решил сделать этот вызов API в отдельном потоке, чтобы нашему клиенту не пришлось больше ждать ответа.
@Override
@Transactional( rollbackFor = DataException.class )
public TaskResponseBean createTask( TaskCreationBean taskCreationBean, UserAccessDetails accessDetails )
throws DataException
{
String googleEventId = "";
try
{
TaskServiceUtil.validateInputBeforeCreatingTask(taskCreationBean, accessDetails);
MatterModel matterModel = matterService.giveMatterIfExistElseThrowException(taskCreationBean.getMatterId(),
owner);
//A task is unique for a user for a matter
taskCommons.throwExceptionIfTaskNameAlreadyExistForTheMatter(taskCreationBean.getTaskName().trim(), owner,
matterModel);
TaskModel savedTask = taskModelRepository.save(savableTask);
if( !NullEmptyUtils.isNull(savableTask.getDueDate()) )
{
final CreateEventBean createEventBean = getCreateEventBean(getEventParticipants(savedTask), savedTask);
calendarTrigerer.triggerEventCreation(createEventBean, savedTask.getId(), null,
GoogleCalendarTrigerer.EVENT_TYPE_CREATE);
}
// Keep track of the list of assignees of a task
if( taskCreationBean.getHaveAssignee() || taskCreationBean.getIsSelfAssigned() )
{
saveTaskAssignedHistory(savedTask, owner, savedTask.getAssignedTo(), false);
}
}
catch( DataException e )
{
LOGGER.error(GeneralConstants.ERROR, e);
if( !NullEmptyUtils.isNullOrEmpty(googleEventId) )
{
LOGGER.info("Deleting google event id {}", googleEventId);
googleCalendarService.deleteGoogleCalendarEvent(googleEventId);
}
throw e;
}
catch( Exception e )
{
LOGGER.error(GeneralConstants.ERROR, e);
if( !NullEmptyUtils.isNullOrEmpty(googleEventId) )
{
LOGGER.info("Deleting google event id {}", googleEventId);
googleCalendarService.deleteGoogleCalendarEvent(googleEventId);
}
throw new DataException(GeneralConstants.EXCEPTION, GeneralConstants.SOMETHING_WENT_WRONG,
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@Async
void triggerEventCreation( CreateEventBean createEventBean, Long taskId, String eventId, String eventType )
throws DataException
{
try
{
TaskModel taskModel = null;
if( !NullEmptyUtils.isNullOrEmpty(taskId) )
{
int retryCount = 0;
Optional<TaskModel> taskModelOptional = taskModelRepository.findByIdAndIsActiveTrue(taskId);
while( !taskModelOptional.isPresent() )
{
System.out.println("NOT PRESENT***********************************************");
taskModelOptional = taskModelRepository.findByIdAndIsActiveTrue(taskId);
if( retryCount++ > 50 )
{
throw new DataException(GeneralConstants.EXCEPTION, "Transaction is unable to commit",
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
taskModel = taskModelOptional.get();
}
switch ( eventType )
{
case EVENT_TYPE_CREATE :
eventId = googleCalendarService.addGoogleCalendarEvent(createEventBean);
System.out.println("ADDED EVENT***********************************************" + eventId);
System.out.println("PRESENT***********************************************");
taskModel.setGoogleEventId(eventId);
taskModelRepository.save(taskModel);
break;
case EVENT_TYPE_DELETE :
NullEmptyUtils.throwExceptionIfInputIsNullOrEmpty(eventId);
googleCalendarService.deleteGoogleCalendarEvent(eventId);
taskModel.setGoogleEventId(null);
taskModel.setIsActive(false);
taskModelRepository.save(taskModel);
break;
case EVENT_TYPE_UPDATE :
NullEmptyUtils.throwExceptionIfInputIsNullOrEmpty(eventId);
NullEmptyUtils.throwExceptionIfInputIsNullOrEmpty(createEventBean);
taskModel.setGoogleEventId(
googleCalendarService.updateGoogleCalendarEvent(eventId, createEventBean));
taskModelRepository.save(taskModel);
break;
default :
throw new DataException(GeneralConstants.EXCEPTION, "Invalid eventType", HttpStatus.BAD_REQUEST);
}
}
catch( DataException e )
{
log.error(GeneralConstants.ERROR, e);
throw e;
}
catch( Exception e )
{
log.error(GeneralConstants.ERROR, e);
throw new DataException(GeneralConstants.EXCEPTION,
"Something went wrong while trigering create event action", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Как я решил (убедитесь, что это работает) при создании события
В отдельном потоке я буду повторяться и ждать, пока задача будет создана, а затем обновить ее с помощью идентификатора события и сохранить его.
Но возникает новая проблема: при обновлении задачи у меня уже есть ее данные в базе данных. В методе обновления я установлю обновленные значения на TaskModel
и сделаю taskModelRepo.save()
, и в отдельном потоке я вызываю API обновления календаря Google, и после успешного вызова API я должен обновить соответствующий TaskModel
и сохранить его.
Проблема здесь в том, что иногда, когда я получаю задачу по идентификатору после успешного вызова Google API, я получаю TaskModel
с не обновленными значениями, так как предыдущая транзакция еще не зафиксирована.
Итак, как обеспечить выполнение нового потока только после того, как будет зафиксирована транзакция метода, из которого он вызван?