001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.hadoop.lib.service.scheduler; 020 021 import org.apache.hadoop.lib.lang.RunnableCallable; 022 import org.apache.hadoop.lib.server.BaseService; 023 import org.apache.hadoop.lib.server.Server; 024 import org.apache.hadoop.lib.server.ServiceException; 025 import org.apache.hadoop.lib.service.Instrumentation; 026 import org.apache.hadoop.lib.service.Scheduler; 027 import org.apache.hadoop.lib.util.Check; 028 import org.slf4j.Logger; 029 import org.slf4j.LoggerFactory; 030 031 import java.text.MessageFormat; 032 import java.util.concurrent.Callable; 033 import java.util.concurrent.ScheduledExecutorService; 034 import java.util.concurrent.ScheduledThreadPoolExecutor; 035 import java.util.concurrent.TimeUnit; 036 037 public class SchedulerService extends BaseService implements Scheduler { 038 private static final Logger LOG = LoggerFactory.getLogger(SchedulerService.class); 039 040 private static final String INST_GROUP = "scheduler"; 041 042 public static final String PREFIX = "scheduler"; 043 044 public static final String CONF_THREADS = "threads"; 045 046 private ScheduledExecutorService scheduler; 047 048 public SchedulerService() { 049 super(PREFIX); 050 } 051 052 @Override 053 public void init() throws ServiceException { 054 int threads = getServiceConfig().getInt(CONF_THREADS, 5); 055 scheduler = new ScheduledThreadPoolExecutor(threads); 056 LOG.debug("Scheduler started"); 057 } 058 059 @Override 060 public void destroy() { 061 try { 062 long limit = System.currentTimeMillis() + 30 * 1000; 063 scheduler.shutdownNow(); 064 while (!scheduler.awaitTermination(1000, TimeUnit.MILLISECONDS)) { 065 LOG.debug("Waiting for scheduler to shutdown"); 066 if (System.currentTimeMillis() > limit) { 067 LOG.warn("Gave up waiting for scheduler to shutdown"); 068 break; 069 } 070 } 071 if (scheduler.isTerminated()) { 072 LOG.debug("Scheduler shutdown"); 073 } 074 } catch (InterruptedException ex) { 075 LOG.warn(ex.getMessage(), ex); 076 } 077 } 078 079 @Override 080 public Class[] getServiceDependencies() { 081 return new Class[]{Instrumentation.class}; 082 } 083 084 @Override 085 public Class getInterface() { 086 return Scheduler.class; 087 } 088 089 @Override 090 public void schedule(final Callable<?> callable, long delay, long interval, TimeUnit unit) { 091 Check.notNull(callable, "callable"); 092 if (!scheduler.isShutdown()) { 093 LOG.debug("Scheduling callable [{}], interval [{}] seconds, delay [{}] in [{}]", 094 new Object[]{callable, delay, interval, unit}); 095 Runnable r = new Runnable() { 096 public void run() { 097 String instrName = callable.getClass().getSimpleName(); 098 Instrumentation instr = getServer().get(Instrumentation.class); 099 if (getServer().getStatus() == Server.Status.HALTED) { 100 LOG.debug("Skipping [{}], server status [{}]", callable, getServer().getStatus()); 101 instr.incr(INST_GROUP, instrName + ".skips", 1); 102 } else { 103 LOG.debug("Executing [{}]", callable); 104 instr.incr(INST_GROUP, instrName + ".execs", 1); 105 Instrumentation.Cron cron = instr.createCron().start(); 106 try { 107 callable.call(); 108 } catch (Exception ex) { 109 instr.incr(INST_GROUP, instrName + ".fails", 1); 110 LOG.error("Error executing [{}], {}", new Object[]{callable, ex.getMessage(), ex}); 111 } finally { 112 instr.addCron(INST_GROUP, instrName, cron.stop()); 113 } 114 } 115 } 116 }; 117 scheduler.scheduleWithFixedDelay(r, delay, interval, unit); 118 } else { 119 throw new IllegalStateException( 120 MessageFormat.format("Scheduler shutting down, ignoring scheduling of [{}]", callable)); 121 } 122 } 123 124 @Override 125 public void schedule(Runnable runnable, long delay, long interval, TimeUnit unit) { 126 schedule((Callable<?>) new RunnableCallable(runnable), delay, interval, unit); 127 } 128 129 }