We have an add-on which makes multiple calls to the JIRA API for creating/updating/deleting configuration objects. Those calls are made in a database transaction so that we can roll back the changes in case something goes wrong during the process. However, since caches are not transaction-aware our add-on may receive wrong data from the cache.
Steps to reproduce:
- Start a thread - thread1. Within it start a database transaction (using the com.atlassian.jira.transaction.Txn API)
- In thread 1 create an issue type using com.atlassian.jira.config.IssueTypeManager.createIssueType(String, String, String) - this will clear the issue types cache
- Start another thread - thread2. Retrieve all issue types using com.atlassian.jira.config.ConstantsManager.getAllIssueTypeObjects() - the result will not contain the newly created issue type, because the transaction in thread1 has not been committed yet
- In thread1, call com.atlassian.jira.config.ConstantsManager.getAllIssueTypeObjects() - the result will again not contain the newly created issue type, although the call is made within the same transaction. That's because all values are read from the cache, which was populated by thread2!
In our case thread1 is our add-on, while thread2 is JIRA Agile, which is querying the issue types. We have also observed this with custom fields, but I guess it applies to all configuration objects which are cached.
This is also a problem in the other direction - thread2 may see data from the caches which is not actually committed to the database and may be rolled back in any moment.
This is serious concurrency issue which may affect any code which uses the JIRA API for managing configuration objects within the boundaries of a database transaction and is very hard to investigate.