Run all effectors by schedule

This article is for Data Center. Visit Cloud

Run all effectors by schedule

This script can be used in ScriptRunner to run effectors by schedule. See ScriptRunner Jobs.

Run effectors
/* * This script allows to start specified or all effectors for chosen structure. * It will ping started effector process until it finishes. * It will NOT acknowledge the process at the end so the process will be available in the structure status bar process list. */ // params def structureId = 14 // target structure ID def effectorIds = [2, 1] // effector IDs to run or empty to run all effectors in structure def processCheckInterval = 1000; // milliseconds // Structure imports import com.almworks.jira.structure.api.StructurePluginHelper import com.almworks.jira.structure.api.auth.StructureAuth import com.almworks.jira.structure.api.effector.instance.EffectorInstanceManager import com.almworks.jira.structure.api.effector.process.EffectorProcessManager import com.almworks.jira.structure.api.error.StructureException import com.almworks.jira.structure.api.forest.ForestSpec import com.almworks.jira.structure.api.forest.ForestService import com.almworks.jira.structure.api.forest.ForestSource import com.almworks.jira.structure.api.StructureComponents import com.almworks.jira.structure.api.item.CoreIdentities import com.almworks.jira.structure.api.permissions.PermissionLevel import com.almworks.jira.structure.api.process.ProcessHandleManager import com.almworks.jira.structure.api.process.ProcessStatus import com.almworks.jira.structure.api.row.RowManager import com.almworks.jira.structure.api.structure.StructureManager import com.almworks.jira.structure.api.util.StructureUtil // ScriptRunner imports import com.onresolve.scriptrunner.runner.customisers.PluginModule import com.onresolve.scriptrunner.runner.customisers.WithPlugin import com.onresolve.scriptrunner.runner.ScriptRunnerImpl // Atlassian import (might be available without the import in some instances, but better safe than sorry) import com.atlassian.jira.component.ComponentAccessor import static java.util.Arrays.asList // switch to plugin @Grab(group = 'com.almworks.jira.structure', module = 'structure-api', version = '*') @WithPlugin('com.almworks.jira.structure') class EffectorRunner { StructureComponents SC = ScriptRunnerImpl.getPluginComponent(StructureComponents) ForestService FS = SC.getForestService() RowManager RM = SC.getRowManager() StructureManager SM = SC.getStructureManager() ProcessHandleManager PHM = SC.getProcessHandleManager() // next components are not available from StructureComponents in Structure 6.x, but who knows :) EffectorInstanceManager EIM = ScriptRunnerImpl.getPluginComponent(EffectorInstanceManager) EffectorProcessManager EPM = ScriptRunnerImpl.getPluginComponent(EffectorProcessManager) def user = StructureAuth.getUser() ForestSource source def structureId def effectorIds def log def processCheckInterval EffectorRunner(def log, def structureId, def effectorIds, def processCheckInterval) { this.structureId = structureId this.effectorIds = effectorIds this.log = log this.processCheckInterval = processCheckInterval try { // check for structure existence and permissions SM.getStructure(structureId, PermissionLevel.VIEW) source = FS.getForestSource(ForestSpec.skeleton(structureId)) } catch (StructureException ex) { log.error("Cant create forest source for structure id=${structureId} for user ${user}.\n${trimStackTrace(ex)}") } } def run() { def caption = "See logs for results." if (source == null) return caption def structureName = FS.getDisplayName(ForestSpec.skeleton(structureId)) def effectors = getEffectorInstances() if (effectors.isEmpty()) { log.warn("No effectors were found.") return caption } if (!effectorIds.isEmpty() && effectorIds.size != effectors.size()) { return caption } log.warn("Starting to execute effectors for structure '${structureName}' for user ${user}") // print effectors list to run effectors.each {ef -> log.warn("\teffector: id=${ef.getId()} ${ef.getModuleKey()} ${ef.getParameters()}") } // start effectors process def processId = runEffectors(effectors) if (processId == null) return caption log.warn("Effector process id=${processId} started.") // await process finish if (awaitFinish(processId)) { // print produced effect records and errors printResults(processId) log.warn("Done.") } else { log.error("Failed.") } return caption } def printResults(def processId) { def records = EPM.getEffectRecords(processId) if (records.isEmpty()) { log.warn("No effect records were produced.") } else if (records.size() > 100) { // just not to spam log.warn("There are ${records.size()} applied effects.") } else { records.each {record -> // choose right log level for errors and applied effects if (record.isError()) { log.error(StructureUtil.getTextInCurrentUserLocale(record.getEffectMessage())) } else { log.warn(StructureUtil.getTextInCurrentUserLocale(record.getEffectMessage())) } } } } // This is blocking method will run until effectors process finish. def awaitFinish(def processId) { def handleId try { def process = EPM.getProcess(processId) handleId = process.getProcessHandleId() } catch (StructureException ex) { log.error("Failed to get process info\n.${trimStackTrace(ex)}") return false } def info = PHM.getInfo(handleId) if (info == null) return false def prevProgress = 0 while (info != null && info.getStatus() != ProcessStatus.FINISHED && sleep()) { info = PHM.getInfo(handleId) if (info.percentComplete != prevProgress) { def process = EPM.getProcess(processId) log.warn("\tprocess complete ${info.getPercentComplete()}%. Status ${process.getStatus()}") prevProgress = info.getPercentComplete() } } return info != null } def sleep() { try { Thread.sleep(processCheckInterval) return true } catch (InterruptedException ex) { log.warn(${trimStackTrace(ex)}) Thread.currentThread().interrupt() return false } return true } def runEffectors(def effectors) { try { return EPM.startProcess(effectors, structureId, false) } catch (StructureException ex) { log.error("Effector process validation failed.\n${trimStackTrace(ex)}") return null } } def getEffectorInstances() { def ids = effectorIds.isEmpty() ? findEffectors() : effectorIds def instances = [] ids.each {id -> try { instances.add(EIM.getEffectorInstance(id)) } catch (StructureException ex) { log.error("Unable to find effector with id=${id}.\n${trimStackTrace(ex)}") } } return instances } def findEffectors() { def effectorIds = [] source.getLatest().getForest().forEach {row -> def rowId = row.left() def itemId = RM.getRow(rowId).getItemId() if (CoreIdentities.isEffector(itemId)) { effectorIds.add(itemId.getLongId()) } } return effectorIds } def trimStackTrace(Exception e) { return asList(e.stackTrace).subList(0, 20).join('\n ') + '\n ...' } } new EffectorRunner(log, structureId, effectorIds, processCheckInterval).run()