Confluence has been updated to version 6.15.9

Introduction

Whenever there are 2 systems that are updating the same information in a distributed manner, conflicts can arise.


Assume

  • Jira Server 1 is connected with Jira Server 2 such that summary and description are synced
  • Every update to the summary or description is automatically sent to the other side and applied to the twin issue.
  • This is bidirectional.  Whenever the twin issue summary is updated, then that information is applied to the local issue


TimeInstance AInstance B
1A1.Summary = A0B1.Summary = A0
2A1.Summary → A1
3
Exalate updates B1.Summary → A1
4
User Updates 
B1.Summary → B1
5Exalate updates
A1.Summary → B1

The question is now, what happens when the summary is updated at the same time on both sides. 


TimeInstance AInstance B
1A1.Summary = A0B1.Summary = A0
2A1.Summary → A1B1.Summary → B1
3Exalate updates
A1.Summary → B1
Exalate updates
B1.Summary → A1

In this case, updates will cross each other.

This is, of course, a situation to be avoided, because the values on both ends are not the same anymore. 


Introducing ConflictHelper

JIRA SERVER

ConflictHelper is an example of an external script for Jira Server which ensures that updates are only done in a safe way.
The ConflictHelper will calculate for each field that has been updated by a user, the most recent change so that the synchronization transactions can be sequenced, and out of sequence updates avoided.

Deploying the ConflictHelper

The example script can be downloaded from here and deployed on the <jira-home>/scripts folder

  • This is an example script - just showing how one can avoid update conflicts.



How to use the ConflictHelper

On the outgoing side, use the send method

ConflictHelper.send()

On the incoming side, use the safeUpdate method as follows

if (ConflictHelper.safeUpdate("summary", "description", "status", "resolution", "mood") {
   // update all fields listed as argument
   issue.summary = replica.summary
   issue.description = replica.description
   issue.resolution = nodeHelper.getResolution(replica.resolution?.name)
   issue.customFields."mood".value = replica.customFields."mood"?.value
   Status.receive()
}

How does it work


  • ConflictHelper.send
    is adding a CustomKey with the name 'ConflictHelper.lastUpdated' to the replica. 
    • This is a JSON serialized map of the last update date of each of the fields
    • ConflictHelper calculates this map from the ChangeHistory of the issue
  • ConflictHelper.safeUpdate(fieldname1, fieldname2 ...)
    Will return false if any of the fields in the method call have been updated later than the updates which will be applied.
    For instance, if the issue.summary has been updated after the update of the summary, then the summary should not be overwritten.

Caveats

  • The time clock on all servers must be identical