Changes are not synchronized with another instance

Originally asked by Ezadin Mahmoud on 24 January 2022 (original question)


Hello Community,

The creation of a ticket in project1 on Instance A( Jira Server v8.14.1 Exalate version 5.2.2-m19-j8) leads to the creation of a ticket in project2 via Exalate on Instance B( Jira Server v8.13.6 Exalate version 5.2.2-m19-j8).
The changes on instance A are synchronized with instance B.
Depending on these changes, the value of a custom field CF in Project2 on B is automatically changed via a scriptrunner listener.
The new value of CF (and any other changes made via the scriptrunner listener) are not automatically synchronized with Project1 on A unless we manually make additional changes to Project2 on B.

How can we have the new value of CF automatically sync directly through Exalate without requiring manual changes?

How can we trigger an Exalate when a value of CF changed via the scriptrunner listener?

Best regards

Ezadin


Comments:

Harold Oconitrillo commented on 24 January 2022

Hi Ezadin,

It is possible to set up a trigger with a specific value. Also, you may set up a pos-function if the trigger does not work.

Kind regards,

Harold Cruz

Ezadin Mahmoud commented on 25 January 2022

Hello Harald,

post-function is not possible/desired. There is no transition to be executed here.

The trigger does not work because it is not possible to check the value change in the customer fields.

as said, changes made by scriptrunner do not cause synchronization, while manual changes can synchronize.

Best regards

Ezadin

Harold Oconitrillo commented on 26 January 2022

Hello Ezadin,

It looks like for some reason the scriptrunner is not sending the events, therefore please send us a video or screenshot of what you are doing in the scriptrunner and based on that we can better understand if the issue is with the scriptrunner or an issue related to Jira synchronization events that does not allow Exalate to pick those changes.

Kind regards,

Harold Cruz

Ezadin Mahmoud commented on 27 January 2022

Hello Harold,

here is my script

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.workflow.WorkflowTransitionUtil;
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl;
import com.atlassian.jira.util.JiraUtils;
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.project.Project
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.model.ChangeItem
import org.apache.log4j.Logger
Logger log = Logger.getLogger("")
log.warn "START"
def changeLog = event?.changeLog
def changeItems = changeLog.getRelated("ChildChangeItem")
def change = changeItems?.find{ it.field == "Suppler-FiledAgainst"}
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issueManager = ComponentAccessor.issueManager
CustomField customField = customFieldManager.getCustomFieldObjectByName("Supplier");
def supplier_filedagainst = customFieldManager.getCustomFieldObjectByName("Suppler-FiledAgainst")
def filedagainst = issue.getCustomFieldValue(supplier_filedagainst)
def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser

def new_supplier=""
if(change){
}
Boolean condition= ((change.oldstring != null) && (change.newstring !=null) && (change.oldstring != change.newstring))
def commentManager = ComponentAccessor.getCommentManager()

if(!condition){
   //no changes found
    return
}
if(condition && (filedagainst == "Supplier Q")){
   //there is a changes
    new_supplier = "Q"
    commentManager.create(issue,user,"The new Supplier: "+new_supplier,false)
}
if(condition && (filedagainst == "Supplier X")){
    new_supplier = "X"
    commentManager.create(issue,user,"The new Supplier: "+new_supplier,false)
}

if(issue.getComponents().size()<1){
    issue.setComponent([component])
}

def cfConfig = customField.getRelevantConfig(issue)
def value = ComponentAccessor.optionsManager.getOptions(cfConfig)?.find { it.toString() == new_supplier }
issue.setCustomFieldValue(customField, value)
issueManager.updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)
log.warn "END"

When the value of the custom field “Suppler-FiledAgainst” is changed on instance A, this change is synchronized with instance B via Exalate.
Then the script works on instance B and changes the value of the “Supplier” field and this works fine.

The problem is that the new value of the “Supplier” or any other changes (e.g.: comments) made in this script are not synchronized with instance A.

Best regards

Ezadin

Ezadin Mahmoud commented on 07 February 2022

Any updates, suggestions ?

Ezadin Mahmoud commented on 25 February 2022

Hello Harold Cruz,

Which Jira event EXALATE triggers on?

Best regards

Ezadin

Harold Oconitrillo commented on 28 February 2022

Hi Ezadin,

Please review this documentation and let me know if this is helpful for you.

https://docs.idalko.com/exalate/x/0QN1Aw

Kind regards,

Harold Cruz

Ezadin Mahmoud commented on 01 March 2022

Hello Harold Cruz,

Unfortunately this does not help me.

In our case we have an already existing connection between two instances/projects A and B.

Compared to your example, in our case also the “Mode” value field in project B is changed from “Sad” to “Happy”, but the new value “Happy” is not synchronized with project A.

Thus the mode remains “Sad” in A.

Best regards

Ezadin

Harold Oconitrillo commented on 01 March 2022

Hello Ezadin Mahmoud,

As a suggestion, please change false to true in the code below and let us know the outcome.

issueManager.updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)

Kind regards,

Harold Cruz

Ezadin Mahmoud commented on 02 March 2022

Hello Harold Cruz,

Changing the value from false to true did not help.

This does not trigger Exalate to synchronize with project A

Best regards

Ezadin

Ariel Aguilar commented on 26 April 2022

Hi Ezadin,

I would like to understand a bit more the problem, and we need to ask if the update of the custom field is leading to an issue update event?

Kind regards,

Ariel

Ezadin Mahmoud commented on 26 April 2022

Hello Ariel,

No updating of the custom field via scriptrunner on project B dose not lead to update on project A.

Best regards

Ezadin

Ariel Aguilar commented on 26 April 2022

Hi again,

From what I understand, is that the sync transaction processing is updating a custom field, and that change needs to be replicated or sync to the destination - or issue pair.

The way that exalate works is that this will happen if:

  • The update of the custom field leads to an update event.
    This is not guaranteed, there are a lot of dependencies that this happens.
  • The update event reaches the registered listener by Exalate.
    In case that the update event is being raised during the processing of the synchronization transaction, it will not be presented again to the registered listener.
  • The update of the script listener is not performed by the proxy authentication context.
    Even in the case that the issue update event reaches the exalate issue event listener, updates performed in that authentication context will be ignored to avoid loops.
  • The outgoing sync script is generating a replica which is different from the previous sent message.
    It can be that for some reason the replica is not different and the transaction will be cancelled.

Kind regards,

Ariel

Ezadin Mahmoud commented on 31 May 2022

Hello Aguilar,

which Jira event triggers EXALATE then?

Best regards

Ezadin

Answer by Serhiy Onyshchenko on 02 June 2022

Hello, Ezadin Mahmoud ,

It could be that Exalate is not picking up the updates because they are made within the same thread that Exalate is performing operations on the issue.
Please, try running all the modifications in a separate thread:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.workflow.WorkflowTransitionUtil;
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl;
import com.atlassian.jira.util.JiraUtils;
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.project.Project
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.model.ChangeItem
import org.apache.log4j.Logger
Thread.start {
    Logger log = Logger.getLogger("")
    log.info("#Supplier script running in 3...")
    Thread.sleep(1000L)
    log.info("2...")
    Thread.sleep(1000L)
    log.info("1...")
    Thread.sleep(1000L)
    log.warn "START"
    def changeLog = event?.changeLog
    def changeItems = changeLog.getRelated("ChildChangeItem")
    def change = changeItems?.find{ it.field == "Suppler-FiledAgainst"}
    def customFieldManager = ComponentAccessor.getCustomFieldManager()
    def issueManager = ComponentAccessor.issueManager
    CustomField customField = customFieldManager.getCustomFieldObjectByName("Supplier");
    def supplier_filedagainst = customFieldManager.getCustomFieldObjectByName("Suppler-FiledAgainst")
    def filedagainst = issue.getCustomFieldValue(supplier_filedagainst)
    def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser

    def new_supplier=""
    if(change){
    }
    Boolean condition= ((change.oldstring != null) && (change.newstring !=null) && (change.oldstring != change.newstring))
    def commentManager = ComponentAccessor.getCommentManager()

    if(!condition){
        //no changes found
        return
    }
    if(condition && (filedagainst == "Supplier Q")){
        //there is a changes
        new_supplier = "Q"
        commentManager.create(issue,user,"The new Supplier: "+new_supplier,false)
    }
    if(condition && (filedagainst == "Supplier X")){
        new_supplier = "X"
        commentManager.create(issue,user,"The new Supplier: "+new_supplier,false)
    }

    if(issue.getComponents().size()<1){
        issue.setComponent([component])
    }

    def cfConfig = customField.getRelevantConfig(issue)
    def value = ComponentAccessor.optionsManager.getOptions(cfConfig)?.find { it.toString() == new_supplier }
    issue.setCustomFieldValue(customField, value)
    issueManager.updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)
    log.warn "END"
}

Regards, Serhiy


Comments:

Ezadin Mahmoud commented on 11 August 2022

Hello Serhiy,

Thank you for your replay.

Unfortunately this does not help.

Best regards

Ezadin

Harold Oconitrillo commented on 22 August 2022

Hi,

Can you please send us the error stack trace?

Kind regards

Ezadin Mahmoud commented on 30 September 2022

Hi

There is no error here. Simply does not work. No error is reported.

Best regards

Support commented on 07 October 2022

Hi Ezadin,

If you run this thread, it will create a separate thread which means a separate process which has a different ID from the current process, are any of the logins that are in this thread to start occurring in your log file? If none, could you please enable logging for Exalate package and then again execute as below?

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.workflow.WorkflowTransitionUtil;
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl;
import com.atlassian.jira.util.JiraUtils;
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.project.Project
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.model.ChangeItem
import org.apache.log4j.Logger
Thread.start {
    Logger log = Logger.getLogger("")
    log.info("#Supplier script running in 3...")
    Thread.sleep(1000L)
    log.info("2...")
    Thread.sleep(1000L)
    log.info("1...")
    Thread.sleep(1000L)
    log.warn "START"
    def changeLog = event?.changeLog
    def changeItems = changeLog.getRelated("ChildChangeItem")
    def change = changeItems?.find{ it.field == "Suppler-FiledAgainst"}
    def customFieldManager = ComponentAccessor.getCustomFieldManager()
    def issueManager = ComponentAccessor.issueManager
    CustomField customField = customFieldManager.getCustomFieldObjectByName("Supplier");
    def supplier_filedagainst = customFieldManager.getCustomFieldObjectByName("Suppler-FiledAgainst")
    def filedagainst = issue.getCustomFieldValue(supplier_filedagainst)
    def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
 
    def new_supplier=""
    if(change){
    }
    Boolean condition= ((change.oldstring != null) && (change.newstring !=null) && (change.oldstring != change.newstring))
    def commentManager = ComponentAccessor.getCommentManager()
 
    if(!condition){
        //no changes found
        return
    }
    if(condition && (filedagainst == "Supplier Q")){
        //there is a changes
        new_supplier = "Q"
        commentManager.create(issue,user,"The new Supplier: "+new_supplier,false)
    }
    if(condition && (filedagainst == "Supplier X")){
        new_supplier = "X"
        commentManager.create(issue,user,"The new Supplier: "+new_supplier,false)
    }
 
    if(issue.getComponents().size()<1){
        issue.setComponent([component])
    }
 
    def cfConfig = customField.getRelevantConfig(issue)
    def value = ComponentAccessor.optionsManager.getOptions(cfConfig)?.find { it.toString() == new_supplier }
    issue.setCustomFieldValue(customField, value)
    issueManager.updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)
    log.warn "END"
}

Please make sure you run all of these modifications in a different thread.

Kind regards,

Exalate support