Status rollback after transition

I've an intermittent trouble when doing a transition in an issue parent.
There is a post function that solves the subtasks and this action is occurring normally.
However, sometimes the parent issue is transitioned but your status back to the previous.
In the history and transitions tab panels I can see that issue is in the final status which it should is.
There is no information in history or log that indicates what is happen.
I assume that is a possible rollback, but nothing is thrown in the log file.

To clarify, the issue below is in 'PRONTO PARA EXPEDIÇÃO' status.

 

Sem título.png

 

 

But seeing the moviments, it should to be in 'EXPEDIDO' status.

There isn't in the workflow a transition that leaves status back on this way.

 

Someone have any ideia how to fix this?

 

Thanks.

2 answers

This widget could not be displayed.

Hi Mário dos Santos,

 

Do you have the code for the post-function that I can look at please?

 

Thanks,

Johnnson

Currently, I'm using it into a listener to reuse in others workflows.

But even though using it in the listener, the blinking continues.

The rate of this failure is more or less one for every 200 issues processed.

 

import groovy.json.JsonOutput
import com.atlassian.jira.issue.*
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.attachment.Attachment
import javax.ws.rs.core.MultivaluedMap
import com.atlassian.jira.util.io.InputStreamConsumer
import org.apache.commons.io.IOUtils
import java.net.HttpURLConnection;
import com.atlassian.jira.issue.fields.*
import java.net.URL;
import groovyx.net.http.HTTPBuilder
import org.apache.commons.codec.binary.Base64
import java.io.OutputStream
import java.io.BufferedInputStream
import groovy.json.JsonSlurper
import groovy.json.JsonOutput 
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.user.ApplicationUser

class Global {
    static String baseUrl = ComponentAccessor.getApplicationProperties().getString("jira.baseurl")
    static String urlAddTags = baseUrl+'/rest/scriptrunner/latest/custom/addTagsToZendesk?'
    static String urlGetAttachmentToken = baseUrl+'/rest/scriptrunner/latest/custom/getTokenForLastAttachment?'
    static String urlSendAttachment = baseUrl+'/rest/scriptrunner/latest/custom/sendAttachment?'
    static String urlAddComment = baseUrl+'/rest/scriptrunner/latest/custom/addComment?'
    static String cfTicket = "customfield_11086"
    static String cfNomeCliente = "customfield_11071"
    static String cfEndCentralDownloads = "customfield_11054"
    static String tipoContrato = "customfield_11037"
}

def issue = event.getIssue()

def commentManager = ComponentAccessor.getCommentManager()
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

CustomField cfTicket = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(Global.cfTicket)
CustomField cfNomeCliente = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(Global.cfNomeCliente)
CustomField cfEndCentralDownloads = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(Global.cfEndCentralDownloads)
CustomField tipoContrato = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(Global.tipoContrato)

def ticket = issue.getCustomFieldValue(cfTicket) as String
ArrayList contratos = issue.getCustomFieldValue(tipoContrato) as ArrayList
def nomeCliente = issue.getCustomFieldValue(cfNomeCliente) as String
def endCentralDownloads = issue.getCustomFieldValue(cfEndCentralDownloads) as String
def issueKey = issue.getKey()

if (ticket != null && nomeCliente != null) {
    
    ticket = ticket.replace("]","")
    ticket = ticket.replace("[","")
    
    String commentValue
    commentValue = "Olá " + nomeCliente + ",\n\n" +
    "A Release Oficial foi expedida e publicada na Central de Downloads.\n" +
    "O pacote pode ser acessado no endereço: " + endCentralDownloads
    
    //Adiciona comentário no JIRA
    commentManager.create(issue, user, commentValue, false)
    //Adiciona comentário no Zendesk
    addComment(issueKey, ticket, commentValue)
    def outputTAG
    if (contratos != null) {
        for (int i = 0; i <= contratos.size(); i++) {
            if (contratos[i].toString() == "CLOUD") {
                outputTAG = "tags=exp_cloud&tags=exp_def&tags=jira_issue_resolvida"
                break
            }
        }
        if (outputTAG==null) {
            outputTAG = "tags=exp_def&tags=jira_issue_resolvida"
        }
        addTag(issueKey, ticket, outputTAG)
    }
}

def issueService = ComponentAccessor.getIssueService()
def userManager = ComponentAccessor.getUserManager()
ApplicationUser userAdmin = userManager.getUserByKey("integrador.jira")

if (!issue.isSubTask()) {
    def subTasks = issue.getSubTaskObjects()
    subTasks.each {
        if (it.getStatus().name == "Associado") {
            def issueInputParameters = issueService.newIssueInputParameters()
            def actionID = 131
            def validationResult = issueService.validateTransition(userAdmin, it.id, actionID,issueInputParameters)
            if (validationResult.isValid()) {
               def issueResult = issueService.transition(user, validationResult)
               if (! issueResult.isValid()) {
                   log.warn("Failed to transition subtask " + it.key + " errors: " + issueResult.errorCollection)
               }
            }
            else {
                log.warn("Could not transition subtask " + it.key + " errors: " + validationResult.errorCollection)
            }
        }  
    }
}

Object addTag(String issueKey, String ticket , String tags) {
    URL url = new URL(Global.urlAddTags + 'issueKey=' + issueKey + '&ticket=' + ticket + '&' + tags)
    HttpURLConnection conn = (HttpURLConnection) url.openConnection()
    conn.setRequestMethod("GET")
    conn.setDoOutput(true)
    def sb = new StringBuffer()
    def is = new BufferedInputStream(conn.getInputStream())
    def br = new BufferedReader(new InputStreamReader(is))
    def inputLine = ""
    while ((inputLine = br.readLine()) != null) {
        sb.append(inputLine)
    }
    return new JsonSlurper().parseText(sb.toString())
}

Object addComment(String issueKey, String ticket, String commentValue) {
    def urlString = Global.urlAddComment + 'issueKey=' + issueKey + '&ticket=' + ticket + '&commentValue=' + URLEncoder.encode(commentValue, "UTF-8")
    URL url = new URL(urlString)
    HttpURLConnection conn = (HttpURLConnection) url.openConnection()
    conn.setRequestMethod("GET")
    conn.setDoOutput(true)
    def sb = new StringBuffer()
    def is = new BufferedInputStream(conn.getInputStream())
    def br = new BufferedReader(new InputStreamReader(is))
    def inputLine = ""
    while ((inputLine = br.readLine()) != null) {
        sb.append(inputLine);
    }
    return new JsonSlurper().parseText(sb.toString())
}
This widget could not be displayed.

Ok and do you get an error on the times that it fails?

No, nothing falls on atlassian-jira.log file around the transition time.

I think can be a bug in JIRA or Scriptrunner maybe.

I'm able to reproduce this exact behavior making a simple script post function like this:

def subTasks = issue.subTaskObjects
subTasks.each { subTask -> 

// Here, make a transition

}

// Here, updating the issue and making external update


When I leave the transitions on subtask by last, like below, the bug go away.

 

// Here, updating the issue and making external update

def subTasks = issue.subTaskObjects
subTasks.each { subTask -> 

// Here, make a transition

}

 

 

But, it isn't the case of my Script, else it would fail every time.

 

Could you test the above condition to rule out a possible problem in my environment, please?

The transition code seems to work fine for me. You say the error where the parent task is left in it's previous status only happens once ever 200 times on average? This might suggest that it is something on the issue that is causing it to fail. Have you looked for trends accross the issues that it is failing for?

Also, which version of JIRA and ScriptRunner are you using?

It seems like this might be a known issue with the IssueService, it might be best to user IssueManager and do issue.setStatus() on the issue then do issue.updateIssue(). This should correctly set the status if the transition fails.

I'm using JIRA 7.1.2 and ScriptRunner 4.3.16

About the trends on fail issues I didn't find apparent similarity.
I was suspecting the number of subtasks (in some cases with 400 or more). But there were parent failure with 30 subtasks, for example.

For the suggestion to use IssueManager instead IssueService, would you think the problem is in update the subtasks?

Because in that scenario, all subtasks are updated correctly. The even problem is in the parent issue. In this way, the update of the status is being doing by standard workflow post functions (only with the mentioned listener like last in list).

Therefore, the listener runs transitioning all subtasks and finishes. The JIRA makes the transition (or, in that case, it doesn't get to do it completely until the end).

The curious thing is that everything seems to happen correctly because it records the history, transitions, comments and after that the problem occurs.

Suggest an answer

Log in or Sign up to answer
Community showcase
Posted Tuesday in Jira

What modern development practices are at the heart of how your team delivers software?

Hey Community mates! Claire here from the Software Product Marketing team. We all know software development changes rapidly, and it's often tough to keep up. But from our research, we've found the h...

306 views 1 4
Join discussion

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you