JSR 352: Is there a way to tell if a particular job execution is a restart or not from within a job? - jsr352

I know how to get the Execution Id and Instance Id of a job using the Job Context. But if i restart a job, is there way to know if the job execution is the first execution or a restart within the job, for instance inside the reader?

No, but there is an open issue asking for that:
https://java.net/bugzilla/show_bug.cgi?id=7473

This is a bit overly complicated (as the other answer noted, there's an issue opened to consider enhancement for the future Batch 1.1).
You could do this:
//
// Assumes JobContext injected into 'jobCtx' field
//
private boolean isRestart() {
JobOperator jo = BatchRuntime.getJobOperator();
JobInstance jobInstance = jo.getJobInstance(jobCtx.getExecutionId());
int numExecutions = jo.getJobExecutions(jobInstance).size();
return numExecutions > 1;
}

Related

How to check if Jenkins build is waiting for input?

In Jenkins' Groovy, how can I detect that some other build is waiting for user input, as triggered by statements like input message: 'Retry?' ok: 'Restart'?
I checked the Executor and Build API docus, but couldn't identify something that matches. executor.isParking() sounded promising, but returns false.
The problem with Florian's answer is that if the input is waiting for a while, possibly across restarts of Jenkins, it might not be the last line in the log.
This is better:
import org.jenkinsci.plugins.workflow.job.WorkflowJob
import org.jenkinsci.plugins.workflow.support.steps.input.InputAction
def jobs = Jenkins.instance.getAllItems(WorkflowJob.class)
jobs.each { job ->
job.builds.each { build ->
if (build.isBuilding() && build.actions.last() instanceof InputAction) {
println "$job.fullName #$build.number"
}
}
}
This one is looking specifically for WorkflowJob jobs but you could change the class to be FreeStyleProject or whatever other kind of thing you want to look for. But checking that the last action is input seems like a good way to know if it's waiting for input.
Stupid as it may be, this is the only hack I found so far:
def isWaitingForInput(WorkflowRun otherBuild) {
def otherBuildsLog = otherBuild.getLog()
return otherBuildsLog.lastIndexOf("0mAbort") >= otherBuildsLog .length() - 8
}
0mAbort is the piece of code that defines the Abort link that the user can click to abort the build while it is waiting for input.

Jenkins Pipeline currentBuild duration time returns always 0

I am trying to get build duration for our report but it always returns 0.
From reading docs, going through Slack plugin source and reading other resources I should be able to do one of the following:
def duration = currentBuild.duration
def duration = currentBuild.durationString
def duration = currentBuild.durationString()
def duration = currentBuild.getDurationString()
none of which works. From my understanding this might be because I am calling this before the build actually finished and so th duration is not available yet.
Structure of the pipeline looks something like this:
node {
try {
stage("Stage 1"){}
stage("Stage 2"){}
} catch (e) {
currentBuild.result = "FAILED"
throw e
} finally {
notifyBuild(currentBuild.result)
}
}
def notifyBuild(String buildStatus = 'STARTED') {
def duration = currentBuild.duration;
}
My question is:
Why don't I get the duration
Is there a way in pipeline to specify "after build" step? From what I read try-catching should work that way
My temporary solution is to use:
int jobDuration = (System.currentTimeMillis() - currentBuild.startTimeInMillis)/1000;
Which works fine, but always gives time in seconds and I think the currentBuild.duration should be smart enough to give different units (?)
Update 2018-02-19, this was fixed with 2.14 release of Pipeline Support API Plugin, see this issue
In unable to find any documentation about when duration is expected to be valid. But judging from the implementation it seems like it's set directly after the run/build completes. I'm guessing that it is available on the currentBuild object since it's the same object that is used for representing currentBuild.previousBuild, which may have completed.
So to answer your questions:
The duration field is only valid after the build has completed.
No, there is no way of specifying an "after build" step.
With that said, I think your workaround is a good solution (may be wrap it in a function and put it in an GPL (Global Public Library).
As for your final bonus question I think the currentBuild.duration should be smart enough to give different units (?). If you are referring to the nicely formatted string, like Took 10min 5sec, currentBuild.duration won't give you any nice formatting since it simply returns a long value with the number of seconds that has elapsed. Instead, what you can do is call hudson.Util#getTimeSpanString(long duration). Like this:
import hudson.Util;
...
echo "Took ${Util.getTimeSpanString(System.currentTimeMillis() - currentBuild.startTimeInMillis)}"
This will return a nicely formatted string with the current build duration.

How to change a Quartz CRON expression dynamically in Grails

I'm actually working in Grails 3.x and I need to use Quartz Cron expressions. I've implemented successfully regular cron expression and works correctly, but now what I need to do is User (from a GUI) change that cron expression for any other he/she wants.
This is my Job
class ScheduleJob
{
static triggers =
{
cron name: 'myTrigger', cronExpression: "*/5 * * * * ?"
}
def execute()
{
println "------ Every 5 seconds"
}
}
I would appreciate so much if someone could help me to know how to do that, thanks for your time. :D
You have a number of options. One thing you can do is call ScheduleJob.schedule(' your cron expression goes here ').
You could also go get the job manager bean from the application context and reconfigure job beans there.
Some of the info at http://www.tothenew.com/blog/removing-triggers-and-rescheduling-a-quartz-2-job-programatically/ might be helpful.

Get input approver user name in Jenkins Workflow plugin

I am trying to get userid who approved an "input" step in workflow jenkins groovy script. Below is the sample script
node('node1'){
stage "test"
input message: 'test'
}
In the workflow UI if a person hits "thumbs up" I want to print his userid in the log. I dont see any option to do it.
def cause = currentBuild.rawBuild.getCause(Cause.UserIdCause)
cause.userId
will print the person who started the build. I have googled this for days but i am not finding anything. Any help here will be greatly appreciated :)
This Jira issue describes how this is likely to work going forward, however it is still open.
In the meantime, the approach of getting the latest ApproverAction via the build actions API was suggested on #Jenkins IRC recently and should work, note it's not sandbox safe.
Something along the lines of the below for getting the most recent approver:
#NonCPS
def getLatestApprover() {
def latest = null
// this returns a CopyOnWriteArrayList, safe for iteration
def acts = currentBuild.rawBuild.getAllActions()
for (act in acts) {
if (act instanceof org.jenkinsci.plugins.workflow.support.steps.input.ApproverAction) {
latest = act.userId
}
}
return latest
}
The JIRA incident referenced u-phoria has been resolved and the fix released.
By setting the submitterParameter to a value, the variable specified by submitterParameter will be populated with the Jenkins user ID that responded to the input field.

How to set up a one-off job trigger at a specified time using Grails Quartz2 plugin

I am using Quartz2 Plugin, and am trying to dynamically trigger a very simple job. When the user performs a certain action, the job should be triggered some certain number of minutes in the future, and only run once.
I have tried using the simple 'schedule' method that takes a date and job data:
def sendTime = new Date()
use(groovy.time.TimeCategory) {
sendTime = sendTime + (connectionInstance.timeout).minutes
println "I will send the job at $sendTime"
}
ReportSmssyncTimeoutJob.schedule(sendTime, [connectionId:params.id])
In this setup, I find that the job actually triggers immediately instead of waiting until 'sendTime'.
My second attempt, after looking at the plugin source, was to use a SimpleTrigger
def sendTime = new Date()
use(groovy.time.TimeCategory) {
sendTime = sendTime + (connectionInstance.timeout).minutes
println "I will send the job at $sendTime"
}
// arguments here are: jobKey='test', startTime=sendTime, repeatCount=0, repeatInterval=1 (zero not allowed), job-arguments)
def trigger = TriggerHelper.simpleTrigger(new JobKey("test"), sendTime, 0, 1, [connectionId:params.id])
ReportSmssyncTimeoutJob.schedule(trigger)
In this setup, the job also triggers immediately. Is there something wrong with the SimpleTrigger implementation which prevents it from waiting until startDate?
Unfortunately, switching to the main 'quartz' plugin (which now has support for Quartz 2) is not an option as I am working on a project that has loads of jobs set up to work with the quartz2 plugin.
I asked this on the Grails mailing list and got the answer: this is a bug in the quartz2 plugin. It should be fixed in the next release (bug was noted in 0.2.3).
Update: tested this in v2.1.6.2 of the quartz2 plugin, and can confirm that both of the approaches in my question now work.

Resources