У меня странная проблема.
Статус - это экземпляр класса класса EndpointStatus (в конструкторе нет заданий)
private EndpointStatus status = new EndpointStatus(1L, EndpointStatus.Status.AVAILABLE);
....omitted....
@POST
@Path("/calculated")
public Response reCalculated(String req,
final @Context SecurityContext securityContext) {
if ( status.isBusy() ) { return Response.ok( status.getCurrentJob() ).build(); }
String uuid = UUID.randomUUID().toString();
status.setStatus(EndpointStatus.Status.BUSY);
CurrentJob job = new CurrentJob();
job.setId(1L);
job.setJobStatus("ACTIVE");
job.setJobId(uuid);
status.setCurrentJob(job);
executorService.execute(() -> {
try {
thymeNewDateRange.getDataForDateRange(thymeDate, null, status);
status.setCurrentJob(null);
} catch (Exception e) {
serverLogger.error(e);
}
});
return Response.accepted(job).build();
}
Итак, здесь я получаю POST
- изменения статуса с AVAILABLE -> BUSY
- создание объекта задания с сгенерированным UUID.
- Затем объект задания устанавливается в статус объекта.
- немедленно верните 202 с UUID (Долгосрочное задание)
Возврат с начального поста: (класс заданий)
{
"id" : 1,
"jobId" : "5d974c2d-e01a-4842-ad5f-1ef7d78901c0",
"jobStatus" : "ACTIVE",
}
здесь все в порядке.Клиент начал запрашивать 5d974c2d-e01a-4842-ad5f-1ef7d78901c0 в качестве URL-адреса и получает тот же JSON обратно, пока результаты не готовы.
, но вскоре после этого
первые несколько запросов (до этого SO сообщения, клиент выполнял 3 запроса, до этого он был 5, поэтому случайный)
status.setCurrentJob(null);
, по-видимому, будет вызвано (ниже долгосрочного задания в методе POST). Это вернетконечная точка от BUSY до AVAILABLE, даже если задание только началось и для его завершения потребуются часы.
После установки нулевого задания конечная точка ответит: (класс состояния, возвращенный, поскольку currentJob имеет значение null)
{
"id" : 1,
"status" : "AVAILABLE",
"currentJob" : null,
"busy" : false
}
, который, в свою очередь, прекратит запрашивать у клиента, поэтому клиент потеряет все данные ..
Не следует
status.setCurrentJob(null);
вызывать сразу после
thymeNewDateRange.getDataForDateRange(thymeDate, null, status);
завершено?Это единственный случай установки задания на null во всем приложении, поэтому оно должно распространяться отсюда?
конечная точка для запроса задания
@GET
@Path("/job")
public Response queryJob(@Context SecurityContext securityContext,
@QueryParam("pid") String pid) {
if( status.getCurrentJob() != null ) {
return Response.ok(status.getCurrentJob()).build();
}
if( status.getStatus() == EndpointStatus.Status.AVAILABLE ) {
//JOB HAS ENDED - but this will still trigger too early
return Response.ok(status).build();
}else {
return Response.ok("ERROR STATE").build();
}
}
Пожалуйста, не стесняйтесь спрашивать все, что я забылупомянуть ... это довольно длинный и сложный пост.
Cheers;)
EDIT ооооо, мне нужна помощь или экзорцист ...
пробовал с volatile (спасибо @paulturnip), но это не помогло
, кроме того проблема, похоже, сохраняется только на "реальном" тестовом сервере.При локальном запуске с localhost: 8080 эта проблема никогда не возникает ...
, но при запуске на сервере это просто происходит.
я добавил регистратор в качестве первой строки в @Path ("/ job ") для входа:
serverLogger.info("STATUS: " + status.getStatus().toString() + " JOB STATUS: " + status.getCurrentJob().getJobStatus() );
И локально, еще раз нет nullPointer.Но как только он запустится на подходящей среде сервера, каким-то образом status.getCurrentJob().getJobStatus()
выдаст исключение NullPointerException, даже если
CurrentJob job = new CurrentJob();
job.setId(1L);
job.setJobStatus("ACTIVE");
job.setJobId(uuid);
status.setCurrentJob(job);
установлено, буквально за один вызов до (/ рассчитано)
EDIT2:
Боб CurrentJob:
@Entity
public class CurrentJob {
@Id
private Long id;
private volatile String jobId;
private volatile String jobStatus;
.... basic getter&setter&constructor ....
Я использую hibernate, так что @Entity и @Id, но я не планировал сохранять этот экземпляр, мне было интересно, если ониможет как-то мешать государству?