Stop cron job via quartz plugin 0.4.2 in grails 1.3.7 - grails

I have grails 1.3.7 and quartz plugin 0.4.2 for cron jobs.
class MyJob {
static triggers = {}
void execute() {
//some doings.
}
}
Somewhere in my code I have dynamic scheduling of my job like that:
MyJob.schedule(cronExpression)
Every time I schedule new cron job it creates new one and it works together with previously created jobs. But I want to replace old cron jobs of MyJob with new one each time.
Maybe I was wrong in my understanding but I tried to add
def concurrent = false
It didn't help.
Is there any way to stop all jobs of some job class?
Thank you!
UPD: As I understand there is no such thing as InterruptableJob in this version of quartz plugin. Am I right?

Finally I've found way how to unschedule job and schedule another one.
First I've added a group for job:
class MyJob {
def group = 'jobGroupName'
static triggers = {}
void execute() {
// some stuff
}
}
Also I've found JobManagerService inside plugin with very useful methods. But I was looking into source codes to get how it works correctly. After some time my solutions become in next code (maybe it's raw yet, but it works):
class MyService {
def jobManagerService
def rescheduleJob() {
def job = jobManagerService.getJob('jobGroupName').first()
Scheduler scheduler = jobManagerService.quartzScheduler
Trigger trigger = scheduler.getTriggersOfJob(job, 'jobGroupName').first()
if (!jobManagerService.unscheduleJob(trigger.group, trigger.name)) {
log.warn('Failed during unscheduling job')
} else {
MyJob.schedule(newCronExpression)
}
}
}
It's not clear sometimes which name and group required in service methods. So debug and sources helped me with this.

Related

How do you modify Jenkins configuration from a shared-library?

Jenkins allows us to grab a Singelton of the running instance with jenkins.get(). I'm trying to build a class in my shared-library that CRUD's the cloud providers. My code looks like this.
#NonCPS
def create(){
Jenkins jenkins = Jenkins.getInstance()
// logic to create cloud
jenkins.clouds.add(tmpCloud)
jenkins.save()
}
#NonCPS
def delete(){
Jenkins jenkins = Jenkins.getInstance()
def newlist = jenkins.clouds.findAll{ it.getDisplayName() != cloud }
if(newlist){
jenkins.clouds.clear()
}
for ( int i = 0; i < newlist.size; i++ ) {
jenkins.clouds.add(newlist[i])
}
jenkins.save()
}
If I run just the create() function the code works as expected, same if I run just the delete(), but if I run both in the same job like this.
cloud.create()
cloud.delete()
Then only the create will work, the delete wont error but it wont do anything either. Is it possible to reinitialize a singleton? I feel like that is what I need to do. I have tried saving the jenkins instance as a field of my class, but that leads to a hudson serializable error. I dont see a way to pass the jenkins singleton around because of CPS issues.

Injecting service in Quartz job in Grails

developing application using Grails 2.5.1 i used Quartz plugin , and created a job successfully , but when i inject a service in this job i get org.quartz.JobExecutionException: java.lang.NullPointerException
here is the Job's code:
class EveryMonthJob {
def usersUtilsService
static triggers = {
cron name: 'EveryOneMonthJob', cronExpression: "* 31 2 L * ?"
}
def execute() {
usersUtilsService.testMe() // getting the exception here
}
}
There are any number of reasons that might not work. If you are creating an instance of the job yourself (as opposed to Spring creating the instance and subjecting it to dependency injection), that would explain why the reference is null. Another explanation could be that you have the property name wrong.
See the project at https://github.com/jeffbrown/sherifquestion. That is a Grails 2.5.1 app that does just what you are describing and it works fine. See https://github.com/jeffbrown/sherifquestion/blob/e0179f836314dccb5f83861ae8466bfd99717995/grails-app/jobs/demo/EveryMonthJob.groovy which looks like this:
class EveryMonthJob {
// generally I would statically type this property but
// am leaving it dynamically typed top be consistent with
// a question being asked...
def usersUtilsService
static triggers = {
simple repeatInterval: 5000l // execute job once in 5 seconds
}
def execute() {
usersUtilsService.testMe() // this works fine
}
}

How can I delete a job using Job DSL plugin(script) in Jenkins?

I am very new to Jenkins and Job DSL plugin. After a little research, I found how to create a job using DSL and now I am trying to delete a job using DSL.
I know to disable a job using this following code:
//create new job
//freeStyleJob("MyJob1", closure = null);
job("MyJob1"){
disabled(true);
}
It is working perfectly fine. But, I couldn't find any method to delete another job in jenkins.
Please help!
Thanks!
To delete a job, you have to set the "Action for removed jobs" option to "Delete" in the "Process Job DSLs" build step configuration. Then remove the job from your script and run the seed job.
Each instance of the Job Dsl plugin tracks what jobs (and views) it creates. When it is run again, you can configure what it does to jobs (and views) that were present the previous time this instance was run, but are not present this time.
Let's a assume you have two files you use to create jobs.
seed_jobdsl.groovy:
job('seed_all') {
steps {
dsl {
external('*_jobdsl.groovy')
// default behavior
// removeAction('IGNORE')
}
}
}
test_jobdsl.groovy:
job('test_stuff') {
steps {
shell('echo "I live!")
}
}
This will leave jobs created by seed_all unchanged even if they are not present in the list of job created the next time seed is run.
To get jobs to be deleted, change your seed job code:
seed_jobdsl.groovy:
job('seed_all') {
steps {
dsl {
external('*_jobdsl.groovy')
removeAction('DELETE')
}
}
}
Now, run seed_all job to apply your change (seed_all overwrites its own configuration when run). Then make the following change:
test_jobdsl.groovy:
job('test_other') {
steps {
shell('echo "The job is dead, long live the new job!"')
}
}
Run seed_all again. You notice test_stuff will be deleted and test_other will be created. If you remove test_jobdsl.groovy and then run seed_all, test_other will be deleted.

Grails Quartz Plugin concurrent not working

I'm having trouble getting my Quartz Job in Grails to run concurrently as expected. Here is what my job looks like. I've commented out the lines that use the Executor plugin but when I don't comment them out, my code works as expected.
import java.util.concurrent.Callable
import org.codehaus.groovy.grails.commons.ConfigurationHolder
class PollerJob {
def concurrent = true
def myService1
def myService2
//def executorService
static triggers = {
cron name: 'pollerTrigger', startDelay:0, cronExpression: ConfigurationHolder.config.poller.cronExpression
}
def execute() {
def config = ConfigurationHolder.config
//Session session = null;
if (config.runPoller == true) {
//def result = executorService.submit({
myService1.doStuff()
myService2.doOtherStuff()
//} as Callable)
}
}
}
In my case, the myService2.doOtherStuff() is taking a very long time to complete which overlaps the next time this job should trigger. I don't mind if they overlap which is why I explicitly added def concurrent = true but it isn't working.
I have version 0.4.2 of the Quartz plugin and Grails 1.3.7. Am I doing something wrong here? Seems like a pretty straightforward feature to use. I'm not opposed to using the Executor plugin but it seems like I shouldn't have to.
I'm not sure it matters but the cronExpression I'm loading from config in this case is meant to execute this job every minute: "0 * * * * ?"
Apparently, there was a hidden config that I was not aware of that was keeping this from working. In my conf folder there was a file called quartz.properties which contained the following property:
org.quartz.threadPool.threadCount = 1
After increasing this number, my job was triggering even when it had not finished the previous execution.

Grails Quartz Job Integration test - Not autowired Job

I'm writing the Integration test for a Quartz Job in a grails application.
I've the Job in grails-app/jobs folder, and if I start the application it works. The problem is that I want to get it in an integration test, but the autowire won't work. The test is like:
class MyJobTest{
MyJob myJob
def setUp(){
assert myJob != null
}
def testExecute(){
//test logic
}
}
but it fails because myJob is null...some help?
Quartz Jobs are not autowired like services are under the test environment. The documentation for the Quartz job also explicitly states that by default it will not execute on schedule under the test environment (you could change that if you want to but I wouldn't). I would just instantiate myJob = new MyJob() in your setUp and call the execute() method to test it. If you're trying to test the triggers you may want to find a way to look at what is inside the triggers {} maybe inspecting the metaClass?
EDIT IN RESPONSE TO COMMENT:
I've never gotten the services out of the application context so that might work. The way I would probably test it is as follows:
Assuming your class looks something like this:
class MyJob {
def myServiceA
def myServiceB
def execute() {
if(myJobLogicToDetermineWhatToDo) {
myServiceA.doStuff(parameter)
} else {
myServiceB.doStuff(parameter)
}
}
}
What you're really wanting to test here is the myJobLogicToDetermineWhatToDo. I would assume that you have (or can easily write) integration and/or unit tests against your services myServiceA and myServiceB to ensure that they are working correctly. I would then write unit tests to test the logic/wiring of your Job to the appropriate service.
#Test
void routeOne() {
def job = new MyJob()
def myServiceA = new Object()
def expectedParameter = "Name"
def wasCalled = false
myServiceA.metaClass.doStuff = {someParameter ->
assert expectedParameter == someParameter
wasCalled = true
}
job.myServiceA = myServiceA
//Setup data to cause myServiceA to be invoked
job.execute()
assert wasCalled
}
Then repeat this process for all of the routes you have through your Job. This way you can isolate your tests down to the smallest part possible and test the logic of the object that you're invoking not the services it is using. I would assume you're using a service because the logic in there is being used by another part of the system. If you're testing the service through this job and for some reason the job goes away then you have to re-write your tests to invoke the service directly. The way that I've proposed you have tests testing the service directly and tests that mock out those service calls. If the job goes away you would simply delete the tests associated with it and you won't loose any test coverage. Kinda long winded but that's how I would approach testing it.

Resources