001 /**
002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
003 * Licensed under the Apache License, Version 2.0 (the "License");
004 * you may not use this file except in compliance with the License.
005 * You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software
010 * distributed under the License is distributed on an "AS IS" BASIS,
011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 * See the License for the specific language governing permissions and
013 * limitations under the License. See accompanying LICENSE file.
014 */
015 package org.apache.oozie.service;
016
017 import org.apache.oozie.client.OozieClient.SYSTEM_MODE;
018 import org.apache.oozie.util.XLog;
019
020 import java.util.concurrent.Callable;
021 import java.util.concurrent.ScheduledExecutorService;
022 import java.util.concurrent.ScheduledThreadPoolExecutor;
023 import java.util.concurrent.TimeUnit;
024
025 /**
026 * This service executes scheduled Runnables and Callables at regular intervals. <p/> It uses a
027 * java.util.concurrent.ScheduledExecutorService. <p/> The {@link #SCHEDULER_THREADS} configuration property indicates
028 * how many threads the scheduler will use to run scheduled commands.
029 */
030 public class SchedulerService implements Service {
031
032 public static final String CONF_PREFIX = Service.CONF_PREFIX + "SchedulerService.";
033
034 public static final String SCHEDULER_THREADS = CONF_PREFIX + "threads";
035
036 private final XLog log = XLog.getLog(getClass());
037
038 private ScheduledExecutorService scheduler;
039
040 /**
041 * Initialize the scheduler service.
042 *
043 * @param services services instance.
044 */
045 @Override
046 public void init(Services services) {
047 scheduler = new ScheduledThreadPoolExecutor(services.getConf().getInt(SCHEDULER_THREADS, 5));
048 }
049
050 /**
051 * Destroy the scheduler service.
052 */
053 @Override
054 public void destroy() {
055 try {
056 long limit = System.currentTimeMillis() + 30 * 1000;// 30 seconds
057 scheduler.shutdownNow();
058 while (!scheduler.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
059 log.info("Waiting for scheduler to shutdown");
060 if (System.currentTimeMillis() > limit) {
061 log.warn("Gave up, continuing without waiting for scheduler to shutdown");
062 break;
063 }
064 }
065 }
066 catch (InterruptedException ex) {
067 log.warn(ex);
068 }
069 }
070
071 /**
072 * Return the public interface for scheduler service.
073 *
074 * @return {@link SchedulerService}.
075 */
076 @Override
077 public Class<? extends Service> getInterface() {
078 return SchedulerService.class;
079 }
080
081 /**
082 * Return the java.util.concurrent.ScheduledExecutorService instance used by the SchedulerService. <p/>
083 *
084 * @return the scheduled executor service instance.
085 */
086 public ScheduledExecutorService getScheduler() {
087 return scheduler;
088 }
089
090 public enum Unit {
091 MILLISEC(1),
092 SEC(1000),
093 MIN(1000 * 60),
094 HOUR(1000 * 60 * 60);
095
096 private long millis;
097
098 private Unit(long millis) {
099 this.millis = millis;
100 }
101
102 private long getMillis() {
103 return millis;
104 }
105
106 }
107
108 /**
109 * Schedule a Callable for execution.
110 *
111 * @param callable callable to schedule for execution.
112 * @param delay delay for first execution since scheduling.
113 * @param interval interval between executions.
114 * @param unit scheduling unit.
115 */
116 public void schedule(final Callable<Void> callable, long delay, long interval, Unit unit) {
117 log.trace("Scheduling callable [{0}], interval [{1}] seconds, delay [{2}] in [{3}]",
118 callable.getClass(), delay, interval, unit);
119 Runnable r = new Runnable() {
120 public void run() {
121 if (Services.get().getSystemMode() == SYSTEM_MODE.SAFEMODE) {
122 log.trace("schedule[run/callable] System is in SAFEMODE. Therefore nothing will run");
123 return;
124 }
125 try {
126 callable.call();
127 }
128 catch (Exception ex) {
129 log.warn("Error executing callable [{0}], {1}", callable.getClass().getSimpleName(),
130 ex.getMessage(), ex);
131 }
132 }
133 };
134 if (!scheduler.isShutdown()) {
135 scheduler.scheduleWithFixedDelay(r, delay * unit.getMillis(), interval * unit.getMillis(),
136 TimeUnit.MILLISECONDS);
137 }
138 else {
139 log.warn("Scheduler shutting down, ignoring scheduling of [{0}]", callable.getClass());
140 }
141 }
142
143 /**
144 * Schedule a Runnable for execution.
145 *
146 * @param runnable Runnable to schedule for execution.
147 * @param delay delay for first execution since scheduling.
148 * @param interval interval between executions.
149 * @param unit scheduling unit.
150 */
151 public void schedule(final Runnable runnable, long delay, long interval, Unit unit) {
152 log.trace("Scheduling runnable [{0}], interval [{1}], delay [{2}] in [{3}]",
153 runnable.getClass(), delay, interval, unit);
154 Runnable r = new Runnable() {
155 public void run() {
156 if (Services.get().getSystemMode() == SYSTEM_MODE.SAFEMODE) {
157 log.trace("schedule[run/Runnable] System is in SAFEMODE. Therefore nothing will run");
158 return;
159 }
160 try {
161 runnable.run();
162 }
163 catch (Exception ex) {
164 log.warn("Error executing runnable [{0}], {1}", runnable.getClass().getSimpleName(),
165 ex.getMessage(), ex);
166 }
167 }
168 };
169 if (!scheduler.isShutdown()) {
170 scheduler.scheduleWithFixedDelay(r, delay * unit.getMillis(), interval * unit.getMillis(),
171 TimeUnit.MILLISECONDS);
172 }
173 else {
174 log.warn("Scheduler shutting down, ignoring scheduling of [{0}]", runnable.getClass());
175 }
176 }
177
178 }