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 }