Problem
IndexingManager.addIndexingQueueEntry() at IndexingManager.java:57-80 immediately dispatches a worker that opens a new Shepherd and reads the target object by id. If the caller queues before committing its own transaction, two failure modes exist:
- Race: the background worker reads state the caller has not yet committed, so the index reflects an older or partial version.
- Rollback survival: if the caller rolls back, the index has still been updated — it now reflects data that was never persisted.
Known sites that queue pre-commit
Recommended fix
Encounter.processPatch(): move the queue call out of processPatch itself and into the afterPatchTransaction() hook (BaseObject.java:332-338) which runs post-commit-and-close. Only Encounter currently overrides that hook (Encounter.java:5345-5360).
MarkedIndividual.mergeIndividual(): move the two addIndexingQueueEntry calls out of mergeIndividual and into the callers (MergeIndividual.java, ScheduledIndividualMerge.java), executed after the caller's commit.
iaResultsSetID.jsp: move the queue calls below the final commitDBTransaction() at line 352.
Severity
Medium. The race/rollback window is narrow (a single background task execution under the 4-thread indexing pool), and opensearchIndexDeep() reads encounters by id at index time so a rolled-back state is usually corrected by the next real mutation. Still, it produces intermittent index/DB divergence that's hard to diagnose.
Problem
IndexingManager.addIndexingQueueEntry()at IndexingManager.java:57-80 immediately dispatches a worker that opens a newShepherdand reads the target object by id. If the caller queues before committing its own transaction, two failure modes exist:Known sites that queue pre-commit
Encounter.processPatch()— queues inline; commit happens later inBaseObject.processPatch.MarkedIndividual.mergeIndividual()— queues both individuals; enclosing servletMergeIndividual.javacommits later.iaResultsSetID.jsp— all three branches queue before the final commit at line 352-354.Recommended fix
Encounter.processPatch(): move the queue call out ofprocessPatchitself and into theafterPatchTransaction()hook (BaseObject.java:332-338) which runs post-commit-and-close. OnlyEncountercurrently overrides that hook (Encounter.java:5345-5360).MarkedIndividual.mergeIndividual(): move the twoaddIndexingQueueEntrycalls out ofmergeIndividualand into the callers (MergeIndividual.java,ScheduledIndividualMerge.java), executed after the caller's commit.iaResultsSetID.jsp: move the queue calls below the finalcommitDBTransaction()at line 352.Relation to #1514 and PR #1547
individualNumberEncounterson encounters) is being fixed in a separate PR that avoids introducing new pre-commit queueing but deliberately does not move these pre-existing pre-commit calls. This is the follow-up ticket tracking that cleanup.IndividualRemoveEncounter(correct) but inherits the pre-commit pattern at the sites above.Severity
Medium. The race/rollback window is narrow (a single background task execution under the 4-thread indexing pool), and
opensearchIndexDeep()reads encounters by id at index time so a rolled-back state is usually corrected by the next real mutation. Still, it produces intermittent index/DB divergence that's hard to diagnose.