Problem Definition
When a full (stop-the-world) Lucene reindex is started, Jira publishes com.atlassian.jira.issue.index.ReindexAllStartedEvent. A matching terminal event is only published when the reindex completes (ReindexAllCompletedEvent) or is cancelled (ReindexAllCancelledEvent). There is no event for a reindex that fails.
Reported code paths in IndexManagerBase.reIndexAll that end without a terminal event:
- getIndexLock() / withReindexLock(...) fails and the method returns -1
- a RuntimeException is thrown during the reindex or post-processing (e.g. IndexingFailureException: Indexing completed with N errors, caused by database connectivity problems)
Apps that pause background work on ReindexAllStartedEvent and resume on a terminal event can't tell a reindex that is still running from one that has already failed. They wait indefinitely.
Suggested Solution
Guarantee exactly one terminal event for every ReindexAllStartedEvent, whatever the outcome. For example:
- add a new @PublicApi ReindexAllFailedEvent, published when a full reindex ends with errors or cannot acquire the index lock, or
- add an outcome/status to an existing terminal event.
Publishing the terminal event in a finally block would ensure that no path leaves a Started event unmatched.
Why this is important
- The reindex events are @PublicApi. While IndexLifecycleManager.isIndexAvailable() was deprecated (10.4 – 11.1), they were the main signal for apps that must not act on search results during a reindex.
- During a full reindex, searches can return empty or partial results without any error. Apps that run JQL from background jobs (synchronisers, automations, generators) need a reliable start/end signal so they don't act on incomplete data.
- With no terminal signal, apps stay paused until Jira restarts or the next successful full reindex. Depending on the app's design, this can block threads and degrade the instance.
Workaround
Don't rely on reindex events alone to resume work. Poll the index state instead, for example:
- IndexLifecycleManager.isIndexAvailable() followed by IndexLifecycleManager.isIndexConsistent(), with short-lived caching. Both are public and non-deprecated from 11.2.0. Note that isIndexAvailable() reflects the local node only.
- For diagnostics, GET /rest/api/2/reindex returns the success, startTime and finishTime of the active or most recent reindex.
Also fix the underlying cause of any failure (for example database connectivity), then run a full reindex again and confirm it completes with no errors.
Notes
Point 1 of JRASERVER-66335 (Suggestion, 2017) describes the same missing terminal events. This request is specifically for a failure/terminal signal.