Details
-
Bug
-
Resolution: Fixed
-
Major
-
17.10.12
-
None
-
Unit
-
Unknown
-
N/A
-
N/A
-
Description
Problem
GET /rest/jobstatus/<id> can return an HTTP 500 with a NullPointerException while the job it reports on is still running:
java.lang.NullPointerException: Cannot invoke "org.xwiki.job.internal.DefaultJobProgressStep.getOffset()" because the return value of "org.xwiki.job.internal.DefaultJobProgressStep.getParent()" is null at org.xwiki.job.internal.DefaultJobProgress.getCurrentLevelOffset(DefaultJobProgress.java:250) at org.xwiki.rest.internal.ModelFactory.toRestJobProgress(ModelFactory.java:1251) at org.xwiki.rest.internal.ModelFactory.toRestJobStatus(ModelFactory.java:1218) at org.xwiki.rest.internal.resources.job.JobStatusResourceImpl.getJobStatus(JobStatusResourceImpl.java:47)
Any UI that polls job status while the job progresses can hit this, and the progress bar it feeds then breaks. It was observed in App Within Minutes: adding an application entry polls /rest/jobstatus/refactoring/create/..., that poll returned 500, the page never reloaded and the operation appeared to hang.
Cause
DefaultJobProgress#getCurrentLevelOffset() evaluates getCurrentStep() twice:
return getCurrentStep().getParent() != null ? getCurrentStep().getParent().getOffset() : getOffset();
currentStep is a plain, non-volatile field that the job thread reassigns as the job progresses, while the REST thread reads it. Between the null check and the dereference the job thread can advance the progress so that the second getCurrentStep() returns the root step, whose parent is null — the NPE therefore happens on the very line meant to guard against it.
The null check was added by XCOMMONS-1167 (9.1), and the double read has been there ever since, so every version from 9.1 onwards is affected. Being a race, it reproduces rarely.
Fix
Read the parent once:
DefaultJobProgressStep parent = getCurrentStep().getParent(); return parent != null ? parent.getOffset() : getOffset();
Occurrence
Seen on CI in XWiki Environment Tests / xwiki-platform / stable-18.4.x #113, where it made two App Within Minutes functional tests time out: LiveTableGeneratorIT.titleField and AppsLiveTableIT.testEditApplication.