We are using a Jira project to manage all our onboarding tasks whenever a new employee joins our department. The information about the teams and their leads are implemented using the components and component leads (and relabelling the field using behaviours). All other data is implemented as custom fields.
Whenever a new employee joins, the manager creates a new "Onboarding" issue and fills out the required fields. After he clicks "Create" a bunch of sub-tasks are created automatically and assigned to different users with different due dates based on the information entered in the parent issue. Also, some of the sub-tasks are linked together using a "depends on" linking type.
I have implemented this using Scriptrunner. For each sub-task I have created a Post Function script call, which is triggered in the Create transition. Those calls are in a particular order, so sub-tasks created later on can link to sub-tasks created earlier.
The problem is, that creating a new onboarding ticket takes a long time and sometimes I run into timeout issues, where the create issue dialog switches back from an inactive state back to an active state, because I have hit some kind of timeout limit, even though the post functions are still running in the background (they all finish successfully).
I have attached one of the scripts, which mostly all look the same. Maybe someone can give me feedback on how to optimize the script, so it might run faster.
/* ========== change values here ============ */
def subtaskComponent = issue.getParentObject().components.first().name /* lead of component (team) from paren issue should be used as sub-task assignee */
def subtaskAssignee = "" /* jira username; overrides component lead if needed */
def subtaskRelDueDate = 14 /* in days relative to main issue due date */
def subtaskLabelIDString = "hrst_0052" /* us this label for the sub-task to identify issue later on in other sub-task create scripts*/
def dependsOnLabelIDs = ["hrst_0004"] /* list of labels from tasks that should later be linked together */
def checklistURL = "https://wiki.karriereservice.at/x/FgJwAw" /* link to specific checklist in confluence for this sub-task */
def subtaskDescription = """Checkliste: $checklistURL""" /* also write link to confluence page into subject for this sub-task */
/* ========================================== */
import com.atlassian.jira.component.ComponentAccessor
import java.sql.Timestamp
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.user.util.DefaultUserManager
import com.atlassian.crowd.embedded.api.User
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.project.Project
import com.atlassian.jira.issue.label.LabelManager
import com.atlassian.jira.config.IssueTypeManager
import com.atlassian.jira.exception.CreateException
import com.atlassian.jira.issue.IssueFactory
import com.atlassian.jira.issue.link.RemoteIssueLinkBuilder
import com.atlassian.jira.bc.issue.link.RemoteIssueLinkService
if (subtaskComponent?.trim()) {
def projectComponentManager = ComponentAccessor.getProjectComponentManager()
def issueProject = issue.getProjectObject()
def foundComponents = projectComponentManager.findByComponentName(issueProject.getId(), subtaskComponent)
issue.setComponent([foundComponents])
def componentLead = issue.components.first().getComponentLead()
ApplicationUser customAssigneeUserObject = null
if (subtaskAssignee?.trim()) {
def userManager = ComponentAccessor.getUserManager() as UserManager
customAssigneeUserObject = userManager.getUserByName(subtaskAssignee)
} // end if
if (customAssigneeUserObject) {
issue.setAssignee(customAssigneeUserObject)
} else if (componentLead) {
issue.setAssignee(componentLead)
}// end if
} // end if
if (subtaskDescription?.trim()) {
issue.description = subtaskDescription.replaceAll(/ /, '')
} // end if
def dateOfEntry = (Date) issue.getParentObject().getCustomFieldValue(customFieldManager.getCustomFieldObject(12830)) // ID of "First Work Day" field
if (dateOfEntry) {
def newDueDate = dateOfEntry + subtaskRelDueDate
issue.setDueDate(new Timestamp((newDueDate).time))
} // end if
doAfterCreate = {
def labelManager = ComponentAccessor.getComponent(LabelManager)
labelManager.addLabel(currentUser, issue.getId(), subtaskLabelIDString, false)
/* Add link to checklist in confluence */
def linkBuilder = new RemoteIssueLinkBuilder()
def serviceUser = ComponentAccessor.userManager.getUserByKey("jenkins")
linkBuilder.issueId(issue.getId())
linkBuilder.relationship("Wiki Page")
linkBuilder.title("Checkliste")
linkBuilder.url(checklistURL)
def remoteIssueLinkService = ComponentAccessor.getComponent(RemoteIssueLinkService)
def validationResult = remoteIssueLinkService.validateCreate(currentUser, linkBuilder.build())
if (validationResult.isValid()) {
remoteIssueLinkService.create(serviceUser, validationResult)
log.debug "Remote link created"
}
else {
log.error validationResult.errorCollection.errorMessages
}
/* link to dependency tickets */
def parentIssue = issue.getParentObject()
def subTaskManager = ComponentAccessor.getSubTaskManager()
def subTasks = subTaskManager.getSubTaskObjects(parentIssue)
subTasks.each() {
def subtaskLabels = it.getLabels()
def dependsOnLabelIDexists = dependsOnLabelIDs.any { subtaskLabels*.label.contains(it) }
if (dependsOnLabelIDexists) {
//10105: 0 = depended on by, 1 = depends on
issueLinkManager.createIssueLink(issue.getId(), it.getId(), Long.parseLong("10105"),Long.valueOf(1), currentUser);
}
} // end each
}
Here are two individual ideas to solve the problem:
I'd also simplify
50 slightly different scripts doing creates is quite an overhead. If you could take (say) 5 of them that create the first (say) 10 subtasks combine them into one so you're only running one script and can optimise that.
The second layer of optimisation might also to pre-calculate and loop. Rather than create st-1, st-2, st-3, etc, build a collection of data that varies between them, then loop the creation (using the same issue-create object repeatedly and altering it on each create). More obscure than the other three options above, and probably less effective in improvement, but "every little helps"
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
...unfortunately, I think all events in Jira are by default synchronous events :-( (and neither multi-threaded)
If time is not critical, maybe you can implement next work-around:
Do you need it to be real time? Could you write a scheduled job that runs every 5minutes and just checks for updated issues (specific fields etc) using JQL. Or have you event listener create an AO entry in the database with the issue key. Then through a scheduled service you can submit the updated issues
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
managers go through the created subtasks immediately after creation, so asynchronous is not an option.
since the prerequisites are quite different for each script it would lead to a myriad of if/else branches in on script.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.