def start(self, name, restart=False, skip_confirm=False, primary_log_path='workflow.log', fail_fast=False): """ Start, resume, or restart an workflow based on its name. If resuming, deletes failed tasks. :param str name: A name for the workflow. Must be unique for this Cosmos session. :param bool restart: If True and the workflow exists, delete it first. :param bool skip_confirm: (If True, do not prompt the shell for input before deleting workflows or files. :param str primary_log_path: The path of the primary log to write to. If None, does not write to a file. Log information is always printed to stderr. :param bool fail_fast: If True, terminate the workflow the first time a Task fails. :param int default_max_attempts: The default maximum number of times to attempt a Task. Otherwise, run all Tasks except those downstream of a failure. :rtype Workflow: :returns: An Workflow instance. """ from .Workflow import Workflow assert os.path.exists( os.getcwd() ), "The current working dir of this environment, %s, does not exist" % os.getcwd( ) # output_dir = os.path.abspath(output_dir) # output_dir = output_dir if output_dir[-1] != '/' else output_dir[0:] # remove trailing slash # prefix_dir = os.path.split(output_dir)[0] # assert os.path.exists(prefix_dir), '%s does not exist' % prefix_dir from ..util.helpers import mkdir # assert isinstance(primary_log_path, basestring) and len(primary_log_path) > 0, 'invalid parimary log path' if primary_log_path is not None and os.path.dirname(primary_log_path): mkdir(os.path.dirname(primary_log_path)) session = self.session old_id = None if restart: wf = session.query(Workflow).filter_by(name=name).first() if wf: old_id = wf.id msg = 'Restarting %s. Are you sure you want to delete the all sql records?' % wf if not skip_confirm and not confirm(msg): raise SystemExit('Quitting') wf.delete(delete_files=False) else: if not skip_confirm and not confirm( 'Workflow with name %s does not exist, ' 'but `restart` is set to True. ' 'Continue by starting a new Workflow?' % name): raise SystemExit('Quitting') # resuming? wf = session.query(Workflow).filter_by(name=name).first() # msg = 'Workflow started, Cosmos v%s' % __version__ if wf: # resuming. if not skip_confirm and not confirm( 'Resuming %s. All non-successful jobs will be deleted, ' 'then any new tasks in the graph will be added and executed. ' 'Are you sure?' % wf): raise SystemExit('Quitting') # assert ex.cwd == output_dir, 'cannot change the output_dir of an workflow being resumed.' wf.successful = False wf.finished_on = None wf.status = WorkflowStatus.resuming # if not os.path.exists(wf.output_dir): # raise IOError('output_directory %s does not exist, cannot resume %s' % (wf.output_dir, wf)) wf.log.info('Resuming %s' % wf) session.add(wf) failed_tasks = [ t for s in wf.stages for t in s.tasks if not t.successful ] n = len(failed_tasks) if n: wf.log.info( 'Deleting %s unsuccessful task(s) from SQL database, delete_files=%s' % (n, False)) for t in failed_tasks: session.delete(t) for stage in filter(lambda s: len(s.tasks) == 0, wf.stages): wf.log.info( 'Deleting stage %s, since it has 0 successful Tasks' % stage) session.delete(stage) else: # start from scratch # if check_output_dir: # assert not os.path.exists(output_dir), 'Workflow.output_dir `%s` already exists.' % (output_dir) wf = Workflow(id=old_id, name=name, manual_instantiation=False, successful=False) # mkdir(output_dir) # make it here so we can start logging to logfile session.add(wf) wf.info['last_cmd_executed'] = get_last_cmd_executed() wf.info['cwd'] = os.getcwd() wf.info['fail_fast'] = fail_fast wf.primary_log_path = primary_log_path wf.log.info('Committing SQL session...') session.commit() session.expunge_all() session.add(wf) wf.log.info('Execution Command: %s' % get_last_cmd_executed()) wf.cosmos_app = self return wf
def start(self, name, restart=False, skip_confirm=False, primary_log_path='workflow.log', fail_fast=False): """ Start, resume, or restart an workflow based on its name. If resuming, deletes failed tasks. :param str name: A name for the workflow. Must be unique for this Cosmos session. :param bool restart: If True and the workflow exists, delete it first. :param bool skip_confirm: (If True, do not prompt the shell for input before deleting workflows or files. :param str primary_log_path: The path of the primary log to write to. If None, does not write to a file. Log information is always printed to stderr. :param bool fail_fast: If True, terminate the workflow the first time a Task fails. :param int default_max_attempts: The default maximum number of times to attempt a Task. Otherwise, run all Tasks except those downstream of a failure. :rtype Workflow: :returns: An Workflow instance. """ from .Workflow import Workflow assert os.path.exists( os.getcwd()), "The current working dir of this environment, %s, does not exist" % os.getcwd() # output_dir = os.path.abspath(output_dir) # output_dir = output_dir if output_dir[-1] != '/' else output_dir[0:] # remove trailing slash # prefix_dir = os.path.split(output_dir)[0] # assert os.path.exists(prefix_dir), '%s does not exist' % prefix_dir from ..util.helpers import mkdir # assert isinstance(primary_log_path, basestring) and len(primary_log_path) > 0, 'invalid parimary log path' if primary_log_path is not None and os.path.dirname(primary_log_path): mkdir(os.path.dirname(primary_log_path)) session = self.session old_id = None if restart: wf = session.query(Workflow).filter_by(name=name).first() if wf: old_id = wf.id msg = 'Restarting %s. Are you sure you want to delete the all sql records?' % wf if not skip_confirm and not confirm(msg): raise SystemExit('Quitting') wf.delete(delete_files=False) else: if not skip_confirm and not confirm('Workflow with name %s does not exist, ' 'but `restart` is set to True. ' 'Continue by starting a new Workflow?' % name): raise SystemExit('Quitting') # resuming? wf = session.query(Workflow).filter_by(name=name).first() # msg = 'Workflow started, Cosmos v%s' % __version__ if wf: # resuming. if not skip_confirm and not confirm('Resuming %s. All non-successful jobs will be deleted, ' 'then any new tasks in the graph will be added and executed. ' 'Are you sure?' % wf): raise SystemExit('Quitting') # assert ex.cwd == output_dir, 'cannot change the output_dir of an workflow being resumed.' wf.successful = False wf.finished_on = None wf.status = WorkflowStatus.resuming # if not os.path.exists(wf.output_dir): # raise IOError('output_directory %s does not exist, cannot resume %s' % (wf.output_dir, wf)) wf.log.info('Resuming %s' % wf) session.add(wf) failed_tasks = [t for s in wf.stages for t in s.tasks if not t.successful] n = len(failed_tasks) if n: wf.log.info('Deleting %s unsuccessful task(s) from SQL database, delete_files=%s' % (n, False)) for t in failed_tasks: session.delete(t) for stage in filter(lambda s: len(s.tasks) == 0, wf.stages): wf.log.info('Deleting stage %s, since it has 0 successful Tasks' % stage) session.delete(stage) else: # start from scratch # if check_output_dir: # assert not os.path.exists(output_dir), 'Workflow.output_dir `%s` already exists.' % (output_dir) wf = Workflow(id=old_id, name=name, manual_instantiation=False, successful=False) # mkdir(output_dir) # make it here so we can start logging to logfile session.add(wf) wf.info['last_cmd_executed'] = get_last_cmd_executed() wf.info['cwd'] = os.getcwd() wf.info['fail_fast'] = fail_fast wf.primary_log_path = primary_log_path wf.log.info('Committing SQL session...') session.commit() session.expunge_all() session.add(wf) wf.log.info('Execution Command: %s' % get_last_cmd_executed()) wf.cosmos_app = self return wf