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 java.util.Date; 018 import java.util.List; 019 020 import org.apache.hadoop.conf.Configuration; 021 import org.apache.oozie.BundleJobBean; 022 import org.apache.oozie.CoordinatorJobBean; 023 import org.apache.oozie.command.bundle.BundlePauseXCommand; 024 import org.apache.oozie.command.bundle.BundleStartXCommand; 025 import org.apache.oozie.command.bundle.BundleUnpauseXCommand; 026 import org.apache.oozie.command.coord.CoordPauseXCommand; 027 import org.apache.oozie.command.coord.CoordUnpauseXCommand; 028 import org.apache.oozie.executor.jpa.BundleJobsGetNeedStartJPAExecutor; 029 import org.apache.oozie.executor.jpa.BundleJobsGetPausedJPAExecutor; 030 import org.apache.oozie.executor.jpa.BundleJobsGetUnpausedJPAExecutor; 031 import org.apache.oozie.executor.jpa.CoordJobsGetPausedJPAExecutor; 032 import org.apache.oozie.executor.jpa.CoordJobsGetUnpausedJPAExecutor; 033 import org.apache.oozie.service.SchedulerService; 034 import org.apache.oozie.service.Service; 035 import org.apache.oozie.service.Services; 036 import org.apache.oozie.util.MemoryLocks; 037 import org.apache.oozie.util.XLog; 038 039 /** 040 * PauseTransitService is the runnable which is scheduled to run at the configured interval, it checks all bundles 041 * to see if they should be paused, un-paused or started. 042 */ 043 public class PauseTransitService implements Service { 044 public static final String CONF_PREFIX = Service.CONF_PREFIX + "PauseTransitService."; 045 public static final String CONF_BUNDLE_PAUSE_START_INTERVAL = CONF_PREFIX + "PauseTransit.interval"; 046 private final static XLog LOG = XLog.getLog(PauseTransitService.class); 047 048 /** 049 * PauseTransitRunnable is the runnable which is scheduled to run at the configured interval, it checks all 050 * bundles to see if they should be paused, un-paused or started. 051 */ 052 static class PauseTransitRunnable implements Runnable { 053 private JPAService jpaService = null; 054 private MemoryLocks.LockToken lock; 055 056 public PauseTransitRunnable() { 057 jpaService = Services.get().get(JPAService.class); 058 if (jpaService == null) { 059 LOG.error("Missing JPAService"); 060 } 061 } 062 063 public void run() { 064 try { 065 // first check if there is some other running instance from the same service; 066 lock = Services.get().get(MemoryLocksService.class).getWriteLock( 067 PauseTransitService.class.getName(), lockTimeout); 068 if (lock == null) { 069 LOG.info("This PauseTransitService instance will" 070 + "not run since there is already an instance running"); 071 } 072 else { 073 LOG.info("Acquired lock for [{0}]", PauseTransitService.class.getName()); 074 075 updateBundle(); 076 updateCoord(); 077 } 078 } 079 catch (Exception ex) { 080 LOG.warn("Exception happened when pausing/unpausing/starting bundle/coord jobs", ex); 081 } 082 finally { 083 // release lock; 084 if (lock != null) { 085 lock.release(); 086 LOG.info("Released lock for [{0}]", PauseTransitService.class.getName()); 087 } 088 } 089 } 090 091 private void updateBundle() { 092 Date d = new Date(); // records the start time of this service run; 093 List<BundleJobBean> jobList = null; 094 // pause bundles as needed; 095 try { 096 jobList = jpaService.execute(new BundleJobsGetUnpausedJPAExecutor(-1)); 097 if (jobList != null) { 098 for (BundleJobBean bundleJob : jobList) { 099 if ((bundleJob.getPauseTime() != null) && !bundleJob.getPauseTime().after(d)) { 100 new BundlePauseXCommand(bundleJob).call(); 101 LOG.debug("Calling BundlePauseXCommand for bundle job = " + bundleJob.getId()); 102 } 103 } 104 } 105 } 106 catch (Exception ex) { 107 LOG.warn("Exception happened when pausing/unpausing/starting Bundle jobs", ex); 108 } 109 // unpause bundles as needed; 110 try { 111 jobList = jpaService.execute(new BundleJobsGetPausedJPAExecutor(-1)); 112 if (jobList != null) { 113 for (BundleJobBean bundleJob : jobList) { 114 if ((bundleJob.getPauseTime() == null || bundleJob.getPauseTime().after(d))) { 115 new BundleUnpauseXCommand(bundleJob).call(); 116 LOG.debug("Calling BundleUnpauseXCommand for bundle job = " + bundleJob.getId()); 117 } 118 } 119 } 120 } 121 catch (Exception ex) { 122 LOG.warn("Exception happened when pausing/unpausing/starting Bundle jobs", ex); 123 } 124 // start bundles as needed; 125 try { 126 jobList = jpaService.execute(new BundleJobsGetNeedStartJPAExecutor(d)); 127 if (jobList != null) { 128 for (BundleJobBean bundleJob : jobList) { 129 bundleJob.setKickoffTime(d); 130 new BundleStartXCommand(bundleJob.getId()).call(); 131 LOG.debug("Calling BundleStartXCommand for bundle job = " + bundleJob.getId()); 132 } 133 } 134 } 135 catch (Exception ex) { 136 LOG.warn("Exception happened when pausing/unpausing/starting Bundle jobs", ex); 137 } 138 } 139 140 private void updateCoord() { 141 Date d = new Date(); // records the start time of this service run; 142 List<CoordinatorJobBean> jobList = null; 143 Configuration conf = Services.get().getConf(); 144 boolean backwardSupportForCoordStatus = conf.getBoolean(StatusTransitService.CONF_BACKWARD_SUPPORT_FOR_COORD_STATUS, false); 145 146 // pause coordinators as needed; 147 try { 148 jobList = jpaService.execute(new CoordJobsGetUnpausedJPAExecutor(-1)); 149 if (jobList != null) { 150 for (CoordinatorJobBean coordJob : jobList) { 151 // if namespace 0.1 is used and backward support is true, then ignore this coord job 152 if (backwardSupportForCoordStatus == true && coordJob.getAppNamespace() != null 153 && coordJob.getAppNamespace().equals(SchemaService.COORDINATOR_NAMESPACE_URI_1)) { 154 continue; 155 } 156 if ((coordJob.getPauseTime() != null) && !coordJob.getPauseTime().after(d)) { 157 new CoordPauseXCommand(coordJob).call(); 158 LOG.debug("Calling CoordPauseXCommand for coordinator job = " + coordJob.getId()); 159 } 160 } 161 } 162 } 163 catch (Exception ex) { 164 LOG.warn("Exception happened when pausing/unpausing Coordinator jobs", ex); 165 } 166 // unpause coordinators as needed; 167 try { 168 jobList = jpaService.execute(new CoordJobsGetPausedJPAExecutor(-1)); 169 if (jobList != null) { 170 for (CoordinatorJobBean coordJob : jobList) { 171 // if namespace 0.1 is used and backward support is true, then ignore this coord job 172 if (backwardSupportForCoordStatus == true && coordJob.getAppNamespace() != null 173 && coordJob.getAppNamespace().equals(SchemaService.COORDINATOR_NAMESPACE_URI_1)) { 174 continue; 175 } 176 if ((coordJob.getPauseTime() == null || coordJob.getPauseTime().after(d))) { 177 new CoordUnpauseXCommand(coordJob).call(); 178 LOG.debug("Calling CoordUnpauseXCommand for coordinator job = " + coordJob.getId()); 179 } 180 } 181 } 182 } 183 catch (Exception ex) { 184 LOG.warn("Exception happened when pausing/unpausing Coordinator jobs", ex); 185 } 186 } 187 } 188 189 /** 190 * Initializes the {@link PauseTransitService}. 191 * 192 * @param services services instance. 193 */ 194 @Override 195 public void init(Services services) { 196 Configuration conf = services.getConf(); 197 Runnable bundlePauseStartRunnable = new PauseTransitRunnable(); 198 services.get(SchedulerService.class).schedule(bundlePauseStartRunnable, 10, 199 conf.getInt(CONF_BUNDLE_PAUSE_START_INTERVAL, 60), SchedulerService.Unit.SEC); 200 } 201 202 /** 203 * Destroy the StateTransit Jobs Service. 204 */ 205 @Override 206 public void destroy() { 207 } 208 209 /** 210 * Return the public interface for the purge jobs service. 211 * 212 * @return {@link PauseTransitService}. 213 */ 214 @Override 215 public Class<? extends Service> getInterface() { 216 return PauseTransitService.class; 217 } 218 }