def ActionProc(context, action_id, worker_id): '''Action process.''' # Step 1: lock the action for execution timestamp = wallclock() result = db_api.action_acquire(context, action_id, worker_id, timestamp) if result is None: LOG.debug(_('Failed locking action "%s" for execution'), action_id) return False # Step 2: materialize the action object action = Action.load(context, action_id=action_id) LOG.info(_LI('Action %(name)s [%(id)s] started'), {'name': six.text_type(action.action), 'id': action.id}) reason = 'Action completed' try: # Step 3: execute the action result, reason = action.execute() # NOTE: The following exception report is not giving useful # information for some reasons. # except Exception as ex: # We catch exception here to make sure the following logics are # executed. # result = action.RES_ERROR # reason = six.text_type(ex) # LOG.error(_('Exception occurred in action execution[%(action)s]: ' # '%(reason)s'), {'action': action.action, # 'reason': reason}) finally: # NOTE: locks on action is eventually released here by status update action.set_status(result, reason)
def start_action(self, worker_id, action_id=None): '''Run the given action in a sub-thread. Release the action lock when the thread finishes? :param workder_id: ID of the worker thread; we fake workers using senlin engines at the moment. :param action_id: ID of the action to be executed. None means the 1st ready action will be scheduled to run. ''' def release(thread, action_id): '''Callback function that will be passed to GreenThread.link().''' # Remove action thread from thread list self.workers.pop(action_id) timestamp = wallclock() if action_id is not None: action = db_api.action_acquire(self.db_session, action_id, worker_id, timestamp) else: action = db_api.action_acquire_1st_ready(self.db_session, worker_id, timestamp) if not action: return th = self.start(action_mod.ActionProc, self.db_session, action.id) self.workers[action.id] = th th.link(release, action.id) return th
def start_action(self, worker_id, action_id=None): '''Run action(s) in sub-thread(s). :param worker_id: ID of the worker thread; we fake workers using senlin engines at the moment. :param action_id: ID of the action to be executed. None means all ready actions will be acquired and scheduled to run. ''' def launch(action_id): '''Launch a sub-thread to run given action.''' th = self.start(action_mod.ActionProc, self.db_session, action_id) self.workers[action_id] = th th.link(release, action_id) return th def release(thread, action_id): '''Callback function that will be passed to GreenThread.link().''' # Remove action thread from thread list self.workers.pop(action_id) actions_launched = 0 if action_id is not None: timestamp = wallclock() action = db_api.action_acquire(self.db_session, action_id, worker_id, timestamp) if action: launch(action.id) actions_launched += 1 batch_size = cfg.CONF.max_actions_per_batch batch_interval = cfg.CONF.batch_interval while True: timestamp = wallclock() action = db_api.action_acquire_1st_ready(self.db_session, worker_id, timestamp) if action: if batch_size > 0 and 'NODE' in action.action: if actions_launched < batch_size: launch(action.id) actions_launched += 1 else: msg = _('Engine %(id)s has launched %(num)s node ' 'actions consecutively, stop scheduling ' 'node action for %(interval)s second...') % { 'id': worker_id, 'num': batch_size, 'interval': batch_interval } LOG.debug(msg) sleep(batch_interval) launch(action.id) actions_launched = 1 else: launch(action.id) else: break
def ActionProc(context, action_id, worker_id): '''Action process.''' # Step 1: materialize the action object action = Action.load(context, action_id=action_id) if action is None: LOG.error(_LE('Action "%s" could not be found.'), action_id) return False # Step 2: lock the action for execution timestamp = wallclock() res = db_api.action_acquire(action.context, action_id, worker_id, timestamp) if res is None: LOG.warning(_LE('Failed in locking action "%s".'), action_id) return False action.owner = res.owner action.start_time = res.start_time # TODO(Anyone): Remove context usage in event module EVENT.info(action.context, action, action.action, 'START') reason = 'Action completed' success = True try: # Step 3: execute the action result, reason = action.execute() except Exception as ex: # We catch exception here to make sure the following logics are # executed. result = action.RES_ERROR reason = six.text_type(ex) LOG.exception(_('Unexpected exception occurred during action ' '%(action)s (%(id)s) execution: %(reason)s'), {'action': action.action, 'id': action.id, 'reason': reason}) success = False finally: # NOTE: locks on action is eventually released here by status update action.set_status(result, reason) return success
def start_action(self, worker_id, action_id=None): '''Run action(s) in sub-thread(s). :param worker_id: ID of the worker thread; we fake workers using senlin engines at the moment. :param action_id: ID of the action to be executed. None means all ready actions will be acquired and scheduled to run. ''' def launch(action_id): '''Launch a sub-thread to run given action.''' th = self.start(action_mod.ActionProc, self.db_session, action_id) self.workers[action_id] = th th.link(release, action_id) return th def release(thread, action_id): '''Callback function that will be passed to GreenThread.link().''' # Remove action thread from thread list self.workers.pop(action_id) if action_id is not None: timestamp = wallclock() action = db_api.action_acquire(self.db_session, action_id, worker_id, timestamp) if action: launch(action.id) while True: timestamp = wallclock() action = db_api.action_acquire_1st_ready(self.db_session, worker_id, timestamp) # TODO(Yanyan Hu): Enable batch control. if action: launch(action.id) else: break
def acquire(cls, context, action_id, owner, timestamp): return db_api.action_acquire(context, action_id, owner, timestamp)