Skip to content

Commit

Permalink
Issue quartz-scheduler#175: setting execution limits via scheduler pr…
Browse files Browse the repository at this point in the history
…operties
  • Loading branch information
mederly committed Aug 22, 2017
1 parent bf2fd54 commit bf317d9
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 3 deletions.
2 changes: 2 additions & 0 deletions TestCategories.properties
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ org.quartz.AnnualCalendarTest=production
org.quartz.impl.execgroups.JdbcJobStoreExecutionLimitationTest=production
org.quartz.impl.execgroups.RamJobStoreExecutionLimitationTest=production
org.quartz.impl.execgroups.ExecutionLimitationRecoveryTest=production
org.quartz.integrations.tests.QuartzExecutionLimitsSettingTest=production
org.quartz.integrations.tests.QuartzExecutionLimitsSettingTest2=production
org.terracotta.quartz.tests.SynchWriteTest=production
org.terracotta.quartz.tests.StartStopStartTest=production
org.terracotta.quartz.tests.spring.SimpleSpringTest=production
Expand Down
43 changes: 40 additions & 3 deletions quartz-core/src/main/java/org/quartz/impl/StdSchedulerFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.security.AccessControlException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

/**
Expand Down Expand Up @@ -191,6 +192,8 @@ public class StdSchedulerFactory implements SchedulerFactory {

public static final String PROP_SCHED_CONTEXT_PREFIX = "org.quartz.context.key";

public static final String PROP_SCHED_EXECUTION_LIMIT_PREFIX = "org.quartz.executionLimit";

public static final String PROP_THREAD_POOL_PREFIX = "org.quartz.threadPool";

public static final String PROP_THREAD_POOL_CLASS = "org.quartz.threadPool.class";
Expand Down Expand Up @@ -708,6 +711,38 @@ else if (schedInstId.equals(SYSTEM_PROPERTY_AS_INSTANCE_ID)) {

Properties schedCtxtProps = cfg.getPropertyGroup(PROP_SCHED_CONTEXT_PREFIX, true);

Properties executionLimitProps = cfg.getPropertyGroup(PROP_SCHED_EXECUTION_LIMIT_PREFIX, true);
Map<String, Integer> executionLimits;
if (executionLimitProps.isEmpty()) {
executionLimits = null;
} else {
executionLimits = new HashMap<>();
for (Map.Entry<Object, Object> e : executionLimitProps.entrySet()) {
String group = (String) e.getKey();
if ("".equals(group)) {
throw new IllegalArgumentException("Unsupported execution group specification: (empty string). "
+ "Please use '_' or 'null' values to specify limit for jobs without execution group.");
} else if ("_".equals(group) || "null".equals(group)) {
group = null;
}
String limitString = (String) e.getValue();
Integer limit;
if (limitString == null || "".equals(limitString) || "none".equals(limitString)
|| "null".equals(limitString) || "unlimited".equals(limitString)) {
limit = null;
} else {
try {
limit = Integer.parseInt(limitString);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("Couldn't parse execution limit specification: '" + limitString
+ "'. Please use a number (including 0) to set a limit, or 'none', 'null', 'unlimited'"
+ " to specify that there should be no limit.");
}
}
executionLimits.put(group, limit);
}
}

// If Proxying to remote scheduler, short-circuit here...
// ~~~~~~~~~~~~~~~~~~
if (rmiProxy) {
Expand Down Expand Up @@ -1323,7 +1358,9 @@ else if (schedInstId.equals(SYSTEM_PROPERTY_AS_INSTANCE_ID)) {

// Create Scheduler ref...
Scheduler scheduler = instantiate(rsrcs, qs);


scheduler.setExecutionLimits(executionLimits);

// set job factory if specified
if(jobFactory != null) {
qs.setJobFactory(jobFactory);
Expand All @@ -1347,7 +1384,7 @@ else if (schedInstId.equals(SYSTEM_PROPERTY_AS_INSTANCE_ID)) {
String val = schedCtxtProps.getProperty((String) key);
scheduler.getContext().put((String)key, val);
}

// fire up job store, and runshell factory

js.setInstanceId(schedInstId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
package org.quartz.integrations.tests;

import org.junit.Test;
import org.quartz.Scheduler;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import static org.junit.Assert.assertEquals;

/**
* Tests setting execution limits via properties
* @author mederly
*/
public class QuartzExecutionLimitsSettingTest extends QuartzMemoryTestSupport {
@Test
public void testParseExecutionLimits() throws Exception {
Map<String, Integer> limits = new HashMap<>(scheduler.getExecutionLimits());
System.out.println("Execution limits as parsed: " + limits);

Map<String, Integer> expected = new HashMap<>();
expected.put("group1", 12);
expected.put("group2", 0);
expected.put("group3", null);
expected.put("group4", null);
expected.put("group5", null);
expected.put("group6", null);
expected.put(null, 11);
expected.put(Scheduler.LIMIT_FOR_OTHER_GROUPS, 42);
assertEquals("Wrong execution limits", expected, limits);
}

@Override
protected Properties createSchedulerProperties() {
Properties props = super.createSchedulerProperties();
props.put("org.quartz.executionLimit.group1", "12");
props.put("org.quartz.executionLimit.group2", "0"); // no threads for group2

// ways to set 'no limit' (i.e. unlimited number)
props.put("org.quartz.executionLimit.group3", "null");
props.put("org.quartz.executionLimit.group4", "none");
props.put("org.quartz.executionLimit.group5", "unlimited");
props.put("org.quartz.executionLimit.group6", "");

// ways to set limit for triggers without an execution group
props.put("org.quartz.executionLimit._", "11");
props.put("org.quartz.executionLimit.null", "11");

// setting default limit for unlisted groups
props.put("org.quartz.executionLimit.*", "42");

return props;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
package org.quartz.integrations.tests;

import org.junit.Test;

import static org.junit.Assert.assertNull;

/**
* Tests setting execution limits via properties (no properties => no limits)
* @author mederly
*/
public class QuartzExecutionLimitsSettingTest2 extends QuartzMemoryTestSupport {
@Test
public void testParseExecutionLimits() throws Exception {
assertNull("Limits present even if they should not", scheduler.getExecutionLimits());
}

}

0 comments on commit bf317d9

Please sign in to comment.