def test_next_retry_datetime(self): delay = datetime.timedelta(seconds=3) delay_squared = datetime.timedelta(seconds=9) max_delay = datetime.timedelta(seconds=10) dag = models.DAG(dag_id='fail_dag') task = BashOperator( task_id='task_with_exp_backoff_and_max_delay', bash_command='exit 1', retries=3, retry_delay=delay, retry_exponential_backoff=True, max_retry_delay=max_delay, dag=dag, owner='airflow', start_date=datetime.datetime(2016, 2, 1, 0, 0, 0)) ti = TI( task=task, execution_date=datetime.datetime.now()) ti.end_date = datetime.datetime.now() ti.try_number = 1 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date+delay) ti.try_number = 2 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date+delay_squared) ti.try_number = 3 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date+max_delay)
def test_next_retry_datetime(self): delay = datetime.timedelta(seconds=3) delay_squared = datetime.timedelta(seconds=9) max_delay = datetime.timedelta(seconds=10) dag = models.DAG(dag_id='fail_dag') task = BashOperator(task_id='task_with_exp_backoff_and_max_delay', bash_command='exit 1', retries=3, retry_delay=delay, retry_exponential_backoff=True, max_retry_delay=max_delay, dag=dag, owner='airflow', start_date=datetime.datetime(2016, 2, 1, 0, 0, 0)) ti = TI(task=task, execution_date=datetime.datetime.now()) ti.end_date = datetime.datetime.now() ti.try_number = 1 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date + delay) ti.try_number = 2 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date + delay_squared) ti.try_number = 3 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date + max_delay)
def test_dag_clear(self): dag = DAG('test_dag_clear', start_date=DEFAULT_DATE, end_date=DEFAULT_DATE + datetime.timedelta(days=10)) task0 = DummyOperator(task_id='test_dag_clear_task_0', owner='test', dag=dag) ti0 = TI(task=task0, execution_date=DEFAULT_DATE) # Next try to run will be try 1 self.assertEqual(ti0.try_number, 1) ti0.run() self.assertEqual(ti0.try_number, 2) dag.clear() ti0.refresh_from_db() self.assertEqual(ti0.try_number, 2) self.assertEqual(ti0.state, State.NONE) self.assertEqual(ti0.max_tries, 1) task1 = DummyOperator(task_id='test_dag_clear_task_1', owner='test', dag=dag, retries=2) ti1 = TI(task=task1, execution_date=DEFAULT_DATE) self.assertEqual(ti1.max_tries, 2) ti1.try_number = 1 # Next try will be 2 ti1.run() self.assertEqual(ti1.try_number, 3) self.assertEqual(ti1.max_tries, 2) dag.clear() ti0.refresh_from_db() ti1.refresh_from_db() # after clear dag, ti2 should show attempt 3 of 5 self.assertEqual(ti1.max_tries, 4) self.assertEqual(ti1.try_number, 3) # after clear dag, ti1 should show attempt 2 of 2 self.assertEqual(ti0.try_number, 2) self.assertEqual(ti0.max_tries, 1)
def setUp(self): super(TestLogView, self).setUp() # Create a custom logging configuration configuration.load_test_config() logging_config = copy.deepcopy(DEFAULT_LOGGING_CONFIG) current_dir = os.path.dirname(os.path.abspath(__file__)) logging_config['handlers']['task']['base_log_folder'] = os.path.normpath( os.path.join(current_dir, 'test_logs')) logging_config['handlers']['task']['filename_template'] = \ '{{ ti.dag_id }}/{{ ti.task_id }}/{{ ts | replace(":", ".") }}/{{ try_number }}.log' # Write the custom logging configuration to a file self.settings_folder = tempfile.mkdtemp() settings_file = os.path.join(self.settings_folder, "airflow_local_settings.py") new_logging_file = "LOGGING_CONFIG = {}".format(logging_config) with open(settings_file, 'w') as handle: handle.writelines(new_logging_file) sys.path.append(self.settings_folder) conf.set('core', 'logging_config_class', 'airflow_local_settings.LOGGING_CONFIG') app = application.create_app(testing=True) self.app = app.test_client() self.session = Session() from airflow.www.views import dagbag dag = DAG(self.DAG_ID, start_date=self.DEFAULT_DATE) task = DummyOperator(task_id=self.TASK_ID, dag=dag) dagbag.bag_dag(dag, parent_dag=dag, root_dag=dag) ti = TaskInstance(task=task, execution_date=self.DEFAULT_DATE) ti.try_number = 1 self.session.merge(ti) self.session.commit()
def test_dag_clear(self): dag = DAG('test_dag_clear', start_date=DEFAULT_DATE, end_date=DEFAULT_DATE + datetime.timedelta(days=10)) task0 = DummyOperator(task_id='test_dag_clear_task_0', owner='test', dag=dag) ti0 = TI(task=task0, execution_date=DEFAULT_DATE) # Next try to run will be try 1 self.assertEqual(ti0.try_number, 1) ti0.run() self.assertEqual(ti0.try_number, 2) dag.clear() ti0.refresh_from_db() self.assertEqual(ti0.try_number, 2) self.assertEqual(ti0.state, State.NONE) self.assertEqual(ti0.max_tries, 1) task1 = DummyOperator(task_id='test_dag_clear_task_1', owner='test', dag=dag, retries=2) ti1 = TI(task=task1, execution_date=DEFAULT_DATE) self.assertEqual(ti1.max_tries, 2) ti1.try_number = 1 # Next try will be 2 ti1.run() self.assertEqual(ti1.try_number, 3) self.assertEqual(ti1.max_tries, 2) dag.clear() ti0.refresh_from_db() ti1.refresh_from_db() # after clear dag, ti2 should show attempt 3 of 5 self.assertEqual(ti1.max_tries, 4) self.assertEqual(ti1.try_number, 3) # after clear dag, ti1 should show attempt 2 of 2 self.assertEqual(ti0.try_number, 2) self.assertEqual(ti0.max_tries, 1)
def kill_zombies(self, zombies, session=None): """ Fail given zombie tasks, which are tasks that haven't had a heartbeat for too long, in the current DagBag. :param zombies: zombie task instances to kill. :type zombies: SimpleTaskInstance :param session: DB session. :type Session. """ for zombie in zombies: if zombie.dag_id in self.dags: dag = self.dags[zombie.dag_id] if zombie.task_id in dag.task_ids: task = dag.get_task(zombie.task_id) ti = TaskInstance(task, zombie.execution_date) # Get properties needed for failure handling from SimpleTaskInstance. ti.start_date = zombie.start_date ti.end_date = zombie.end_date ti.try_number = zombie.try_number ti.state = zombie.state ti.test_mode = configuration.getboolean( 'core', 'unit_test_mode') ti.handle_failure("{} detected as zombie".format(ti), ti.test_mode, ti.get_template_context()) self.log.info('Marked zombie job %s as %s', ti, ti.state) Stats.incr('zombies_killed') session.commit()
def setUp(self): super(TestLogView, self).setUp() # Create a custom logging configuration configuration.load_test_config() logging_config = copy.deepcopy(DEFAULT_LOGGING_CONFIG) current_dir = os.path.dirname(os.path.abspath(__file__)) logging_config['handlers']['file.task'][ 'base_log_folder'] = os.path.normpath( os.path.join(current_dir, 'test_logs')) logging_config['handlers']['file.task']['filename_template'] = \ '{{ ti.dag_id }}/{{ ti.task_id }}/{{ ts | replace(":", ".") }}/{{ try_number }}.log' # Write the custom logging configuration to a file self.settings_folder = tempfile.mkdtemp() settings_file = os.path.join(self.settings_folder, "airflow_local_settings.py") new_logging_file = "LOGGING_CONFIG = {}".format(logging_config) with open(settings_file, 'w') as handle: handle.writelines(new_logging_file) sys.path.append(self.settings_folder) conf.set('core', 'logging_config_class', 'airflow_local_settings.LOGGING_CONFIG') app = application.create_app(testing=True) self.app = app.test_client() self.session = Session() from airflow.www.views import dagbag dag = DAG(self.DAG_ID, start_date=self.DEFAULT_DATE) task = DummyOperator(task_id=self.TASK_ID, dag=dag) dagbag.bag_dag(dag, parent_dag=dag, root_dag=dag) ti = TaskInstance(task=task, execution_date=self.DEFAULT_DATE) ti.try_number = 1 self.session.merge(ti) self.session.commit()
def test_log_file_template_with_run_task(self): """Verify that the taskinstance has the right context for log_filename_template""" with mock.patch.object(task_command, "_run_task_by_selected_method"): with conf_vars({('core', 'dags_folder'): self.dag_path}): # increment the try_number of the task to be run dag = DagBag().get_dag(self.dag_id) task = dag.get_task(self.task_id) with create_session() as session: dag.create_dagrun( execution_date=self.execution_date, start_date=timezone.utcnow(), state=State.RUNNING, run_type=DagRunType.MANUAL, session=session, ) ti = TaskInstance(task, self.execution_date) ti.refresh_from_db(session=session, lock_for_update=True) ti.try_number = 1 # not running, so starts at 0 session.merge(ti) log_file_path = os.path.join( os.path.dirname(self.ti_log_file_path), "2.log") try: task_command.task_run( self.parser.parse_args(self.task_args)) assert os.path.exists(log_file_path) finally: try: os.remove(log_file_path) except OSError: pass
def test_next_retry_datetime(self): delay = datetime.timedelta(seconds=30) max_delay = datetime.timedelta(minutes=60) dag = models.DAG(dag_id='fail_dag') task = BashOperator( task_id='task_with_exp_backoff_and_max_delay', bash_command='exit 1', retries=3, retry_delay=delay, retry_exponential_backoff=True, max_retry_delay=max_delay, dag=dag, owner='airflow', start_date=timezone.datetime(2016, 2, 1, 0, 0, 0)) ti = TI( task=task, execution_date=DEFAULT_DATE) ti.end_date = pendulum.instance(timezone.utcnow()) dt = ti.next_retry_datetime() # between 30 * 2^0.5 and 30 * 2^1 (15 and 30) period = ti.end_date.add(seconds=30) - ti.end_date.add(seconds=15) self.assertTrue(dt in period) ti.try_number = 3 dt = ti.next_retry_datetime() # between 30 * 2^2 and 30 * 2^3 (120 and 240) period = ti.end_date.add(seconds=240) - ti.end_date.add(seconds=120) self.assertTrue(dt in period) ti.try_number = 5 dt = ti.next_retry_datetime() # between 30 * 2^4 and 30 * 2^5 (480 and 960) period = ti.end_date.add(seconds=960) - ti.end_date.add(seconds=480) self.assertTrue(dt in period) ti.try_number = 9 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date + max_delay) ti.try_number = 50 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date + max_delay)
def test_next_retry_datetime(self): delay = datetime.timedelta(seconds=30) max_delay = datetime.timedelta(minutes=60) dag = models.DAG(dag_id='fail_dag') task = BashOperator( task_id='task_with_exp_backoff_and_max_delay', bash_command='exit 1', retries=3, retry_delay=delay, retry_exponential_backoff=True, max_retry_delay=max_delay, dag=dag, owner='airflow', start_date=timezone.datetime(2016, 2, 1, 0, 0, 0)) ti = TI( task=task, execution_date=DEFAULT_DATE) ti.end_date = pendulum.instance(timezone.utcnow()) dt = ti.next_retry_datetime() # between 30 * 2^0.5 and 30 * 2^1 (15 and 30) period = ti.end_date.add(seconds=30) - ti.end_date.add(seconds=15) self.assertTrue(dt in period) ti.try_number = 3 dt = ti.next_retry_datetime() # between 30 * 2^2 and 30 * 2^3 (120 and 240) period = ti.end_date.add(seconds=240) - ti.end_date.add(seconds=120) self.assertTrue(dt in period) ti.try_number = 5 dt = ti.next_retry_datetime() # between 30 * 2^4 and 30 * 2^5 (480 and 960) period = ti.end_date.add(seconds=960) - ti.end_date.add(seconds=480) self.assertTrue(dt in period) ti.try_number = 9 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date + max_delay) ti.try_number = 50 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date + max_delay)
def test_next_retry_datetime(self): delay = datetime.timedelta(seconds=30) max_delay = datetime.timedelta(minutes=60) dag = models.DAG(dag_id='fail_dag') task = BashOperator( task_id='task_with_exp_backoff_and_max_delay', bash_command='exit 1', retries=3, retry_delay=delay, retry_exponential_backoff=True, max_retry_delay=max_delay, dag=dag, owner='airflow', start_date=datetime.datetime(2016, 2, 1, 0, 0, 0)) ti = TI( task=task, execution_date=DEFAULT_DATE) ti.end_date = datetime.datetime.now() ti.try_number = 1 dt = ti.next_retry_datetime() # between 30 * 2^0.5 and 30 * 2^1 (15 and 30) self.assertEqual(dt, ti.end_date + datetime.timedelta(seconds=20.0)) ti.try_number = 4 dt = ti.next_retry_datetime() # between 30 * 2^2 and 30 * 2^3 (120 and 240) self.assertEqual(dt, ti.end_date + datetime.timedelta(seconds=181.0)) ti.try_number = 6 dt = ti.next_retry_datetime() # between 30 * 2^4 and 30 * 2^5 (480 and 960) self.assertEqual(dt, ti.end_date + datetime.timedelta(seconds=825.0)) ti.try_number = 9 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date+max_delay) ti.try_number = 50 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date+max_delay)
def test_next_retry_datetime(self): delay = datetime.timedelta(seconds=30) max_delay = datetime.timedelta(minutes=60) dag = models.DAG(dag_id='fail_dag') task = BashOperator( task_id='task_with_exp_backoff_and_max_delay', bash_command='exit 1', retries=3, retry_delay=delay, retry_exponential_backoff=True, max_retry_delay=max_delay, dag=dag, owner='airflow', start_date=datetime.datetime(2016, 2, 1, 0, 0, 0)) ti = TI( task=task, execution_date=DEFAULT_DATE) ti.end_date = datetime.datetime.now() ti.try_number = 1 dt = ti.next_retry_datetime() # between 30 * 2^0.5 and 30 * 2^1 (15 and 30) self.assertEqual(dt, ti.end_date + datetime.timedelta(seconds=20.0)) ti.try_number = 4 dt = ti.next_retry_datetime() # between 30 * 2^2 and 30 * 2^3 (120 and 240) self.assertEqual(dt, ti.end_date + datetime.timedelta(seconds=181.0)) ti.try_number = 6 dt = ti.next_retry_datetime() # between 30 * 2^4 and 30 * 2^5 (480 and 960) self.assertEqual(dt, ti.end_date + datetime.timedelta(seconds=825.0)) ti.try_number = 9 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date+max_delay) ti.try_number = 50 dt = ti.next_retry_datetime() self.assertEqual(dt, ti.end_date+max_delay)
def tis(dags): dag, dag_removed = dags ti = TaskInstance( task=DummyOperator(task_id=TASK_ID, dag=dag), execution_date=DEFAULT_DATE, ) ti.try_number = 1 ti_removed_dag = TaskInstance( task=DummyOperator(task_id=TASK_ID, dag=dag_removed), execution_date=DEFAULT_DATE, ) ti_removed_dag.try_number = 1 with create_session() as session: session.merge(ti) session.merge(ti_removed_dag) yield ti, ti_removed_dag with create_session() as session: session.query(TaskInstance).delete()
def test_try_number(self): """ Test the try_number accessor behaves in various running states """ dag = models.DAG(dag_id='test_check_and_change_state_before_execution') task = DummyOperator(task_id='task', dag=dag, start_date=DEFAULT_DATE) ti = TI(task=task, execution_date=timezone.utcnow()) self.assertEqual(1, ti.try_number) ti.try_number = 2 ti.state = State.RUNNING self.assertEqual(2, ti.try_number) ti.state = State.SUCCESS self.assertEqual(3, ti.try_number)
def test_try_number(self): """ Test the try_number accessor behaves in various running states """ dag = models.DAG(dag_id='test_check_and_change_state_before_execution') task = DummyOperator(task_id='task', dag=dag, start_date=DEFAULT_DATE) ti = TI(task=task, execution_date=timezone.utcnow()) self.assertEqual(1, ti.try_number) ti.try_number = 2 ti.state = State.RUNNING self.assertEqual(2, ti.try_number) ti.state = State.SUCCESS self.assertEqual(3, ti.try_number)
def test_dag_clear(self): dag = DAG('test_dag_clear', start_date=DEFAULT_DATE, end_date=DEFAULT_DATE + datetime.timedelta(days=10)) task0 = DummyOperator(task_id='test_dag_clear_task_0', owner='test', dag=dag) ti0 = TI(task=task0, execution_date=DEFAULT_DATE) dag.create_dagrun( execution_date=ti0.execution_date, state=State.RUNNING, run_type=DagRunType.SCHEDULED, ) # Next try to run will be try 1 assert ti0.try_number == 1 ti0.run() assert ti0.try_number == 2 dag.clear() ti0.refresh_from_db() assert ti0.try_number == 2 assert ti0.state == State.NONE assert ti0.max_tries == 1 task1 = DummyOperator(task_id='test_dag_clear_task_1', owner='test', dag=dag, retries=2) ti1 = TI(task=task1, execution_date=DEFAULT_DATE) assert ti1.max_tries == 2 ti1.try_number = 1 # Next try will be 2 ti1.run() assert ti1.try_number == 3 assert ti1.max_tries == 2 dag.clear() ti0.refresh_from_db() ti1.refresh_from_db() # after clear dag, ti2 should show attempt 3 of 5 assert ti1.max_tries == 4 assert ti1.try_number == 3 # after clear dag, ti1 should show attempt 2 of 2 assert ti0.try_number == 2 assert ti0.max_tries == 1
def test_file_task_handler_running(self): def task_callable(ti, **kwargs): ti.log.info("test") dag = DAG('dag_for_testing_file_task_handler', start_date=DEFAULT_DATE) task = PythonOperator( task_id='task_for_testing_file_log_handler', dag=dag, python_callable=task_callable, ) ti = TaskInstance(task=task, execution_date=DEFAULT_DATE) ti.try_number = 2 ti.state = State.RUNNING logger = ti.log ti.log.disabled = False file_handler = next( (handler for handler in logger.handlers if handler.name == FILE_TASK_HANDLER), None ) assert file_handler is not None set_context(logger, ti) assert file_handler.handler is not None # We expect set_context generates a file locally. log_filename = file_handler.handler.baseFilename assert os.path.isfile(log_filename) assert log_filename.endswith("2.log"), log_filename logger.info("Test") # Return value of read must be a tuple of list and list. logs, metadatas = file_handler.read(ti) assert isinstance(logs, list) # Logs for running tasks should show up too. assert isinstance(logs, list) assert isinstance(metadatas, list) assert len(logs) == 2 assert len(logs) == len(metadatas) assert isinstance(metadatas[0], dict) # Remove the generated tmp log file. os.remove(log_filename)
def test_file_task_handler_running(self): def task_callable(ti, **kwargs): ti.log.info("test") dag = DAG('dag_for_testing_file_task_handler', start_date=DEFAULT_DATE) task = PythonOperator( task_id='task_for_testing_file_log_handler', dag=dag, python_callable=task_callable, provide_context=True ) ti = TaskInstance(task=task, execution_date=DEFAULT_DATE) ti.try_number = 2 ti.state = State.RUNNING logger = ti.log ti.log.disabled = False file_handler = next((handler for handler in logger.handlers if handler.name == FILE_TASK_HANDLER), None) self.assertIsNotNone(file_handler) set_context(logger, ti) self.assertIsNotNone(file_handler.handler) # We expect set_context generates a file locally. log_filename = file_handler.handler.baseFilename self.assertTrue(os.path.isfile(log_filename)) self.assertTrue(log_filename.endswith("2.log"), log_filename) logger.info("Test") # Return value of read must be a tuple of list and list. logs, metadatas = file_handler.read(ti) self.assertTrue(isinstance(logs, list)) # Logs for running tasks should show up too. self.assertTrue(isinstance(logs, list)) self.assertTrue(isinstance(metadatas, list)) self.assertEqual(len(logs), 2) self.assertEqual(len(logs), len(metadatas)) self.assertTrue(isinstance(metadatas[0], dict)) # Remove the generated tmp log file. os.remove(log_filename)
def setUp(self): super(TestLogView, self).setUp() configuration.load_test_config() logging_config = copy.deepcopy(DEFAULT_LOGGING_CONFIG) current_dir = os.path.dirname(os.path.abspath(__file__)) logging_config['handlers']['file.task'][ 'base_log_folder'] = os.path.normpath( os.path.join(current_dir, 'test_logs')) logging.config.dictConfig(logging_config) app = application.create_app(testing=True) self.app = app.test_client() self.session = Session() from airflow.www.views import dagbag dag = DAG(self.DAG_ID, start_date=self.DEFAULT_DATE) task = DummyOperator(task_id=self.TASK_ID, dag=dag) dagbag.bag_dag(dag, parent_dag=dag, root_dag=dag) ti = TaskInstance(task=task, execution_date=self.DEFAULT_DATE) ti.try_number = 1 self.session.merge(ti) self.session.commit()
def test_file_task_handler_running(self): def task_callable(ti, **kwargs): ti.log.info("test") dag = DAG('dag_for_testing_file_task_handler', start_date=DEFAULT_DATE) task = PythonOperator(task_id='task_for_testing_file_log_handler', dag=dag, python_callable=task_callable, provide_context=True) ti = TaskInstance(task=task, execution_date=DEFAULT_DATE) ti.try_number = 2 ti.state = State.RUNNING logger = ti.log ti.log.disabled = False file_handler = next((handler for handler in logger.handlers if handler.name == FILE_TASK_HANDLER), None) self.assertIsNotNone(file_handler) set_context(logger, ti) self.assertIsNotNone(file_handler.handler) # We expect set_context generates a file locally. log_filename = file_handler.handler.baseFilename self.assertTrue(os.path.isfile(log_filename)) self.assertTrue(log_filename.endswith("2.log"), log_filename) logger.info("Test") # Return value of read must be a list. logs = file_handler.read(ti) self.assertTrue(isinstance(logs, list)) # Logs for running tasks should show up too. self.assertEqual(len(logs), 2) # Remove the generated tmp log file. os.remove(log_filename)
def create_dagrun_from_dbnd_run( databand_run, dag, execution_date, run_id, state=State.RUNNING, external_trigger=False, conf=None, session=None, ): """ Create new DagRun and all relevant TaskInstances """ dagrun = ( session.query(DagRun) .filter(DagRun.dag_id == dag.dag_id, DagRun.execution_date == execution_date) .first() ) if dagrun is None: if AIRFLOW_VERSION_2: from airflow.utils.types import DagRunType version_specific_params = dict( state=state, run_type=DagRunType.BACKFILL_JOB ) else: version_specific_params = dict(_state=state) dagrun = DagRun( run_id=run_id, execution_date=execution_date, start_date=dag.start_date, external_trigger=external_trigger, dag_id=dag.dag_id, conf=conf, **version_specific_params, ) session.add(dagrun) else: logger.warning("Running with existing airflow dag run %s", dagrun) dagrun.dag = dag dagrun.run_id = run_id session.commit() # create the associated task instances # state is None at the moment of creation # dagrun.verify_integrity(session=session) # fetches [TaskInstance] again # tasks_skipped = databand_run.tasks_skipped # we can find a source of the completion, but also, # sometimes we don't know the source of the "complete" TI = TaskInstance tis = ( session.query(TI) .filter(TI.dag_id == dag.dag_id, TI.execution_date == execution_date) .all() ) tis = {ti.task_id: ti for ti in tis} for af_task in dag.tasks: ti = tis.get(af_task.task_id) if ti is None: ti = TaskInstance(af_task, execution_date=execution_date) ti.start_date = timezone.utcnow() ti.end_date = timezone.utcnow() session.add(ti) task_run = databand_run.get_task_run_by_af_id(af_task.task_id) # all tasks part of the backfill are scheduled to dagrun # Set log file path to expected airflow log file path task_run.log.local_log_file.path = compute_log_filepath_from_ti( ti, execution_date ) if task_run.is_reused: # this task is completed and we don't need to run it anymore ti.state = State.SUCCESS ti.try_number = 1 session.commit() return dagrun