def call_runner(self, runner): uid_context = UniqueID(runner.node.unique_id) with RUNNING_STATE, uid_context: startctx = TimestampNamed('node_started_at') index = self.index_offset(runner.node_index) extended_metadata = ModelMetadata(runner.node, index) with startctx, extended_metadata: logger.debug('Began running node {}'.format( runner.node.unique_id)) status: Dict[str, str] try: result = runner.run_with_hooks(self.manifest) status = runner.get_result_status(result) finally: finishctx = TimestampNamed('node_finished_at') with finishctx, DbtModelState(status): logger.debug('Finished running node {}'.format( runner.node.unique_id)) fail_fast = getattr(self.config.args, 'fail_fast', False) if result.status in (NodeStatus.Error, NodeStatus.Fail) and fail_fast: self._raise_next_tick = FailFastException( message='Failing early due to test failure or runtime error', result=result, node=getattr(result, 'node', None) ) elif result.status == NodeStatus.Error and self.raise_on_first_error(): # if we raise inside a thread, it'll just get silently swallowed. # stash the error message we want here, and it will check the # next 'tick' - should be soon since our thread is about to finish! self._raise_next_tick = RuntimeException(result.message) return result
def call_runner(self, runner): uid_context = UniqueID(runner.node.unique_id) with RUNNING_STATE, uid_context: startctx = TimestampNamed('node_started_at') index = self.index_offset(runner.node_index) extended_metadata = ModelMetadata(runner.node, index) with startctx, extended_metadata: logger.debug('Began running node {}'.format( runner.node.unique_id)) status = 'error' # we must have an error if we don't see this try: result = runner.run_with_hooks(self.manifest) status = runner.get_result_status(result) finally: finishctx = TimestampNamed('node_finished_at') with finishctx, DbtModelState(status): logger.debug('Finished running node {}'.format( runner.node.unique_id)) if result.error is not None and self.raise_on_first_error(): # if we raise inside a thread, it'll just get silently swallowed. # stash the error message we want here, and it will check the # next 'tick' - should be soon since our thread is about to finish! self._raise_next_tick = result.error return result
def run_hooks(self, adapter, hook_type: RunHookType, extra_context): ordered_hooks = self.get_hooks_by_type(hook_type) # on-run-* hooks should run outside of a transaction. This happens # b/c psycopg2 automatically begins a transaction when a connection # is created. adapter.clear_transaction() if not ordered_hooks: return num_hooks = len(ordered_hooks) plural = 'hook' if num_hooks == 1 else 'hooks' with TextOnly(): print_timestamped_line("") print_timestamped_line('Running {} {} {}'.format( num_hooks, hook_type, plural)) startctx = TimestampNamed('node_started_at') finishctx = TimestampNamed('node_finished_at') for idx, hook in enumerate(ordered_hooks, start=1): sql = self.get_hook_sql(adapter, hook, idx, num_hooks, extra_context) hook_text = '{}.{}.{}'.format(hook.package_name, hook_type, hook.index) hook_meta_ctx = HookMetadata(hook, self.index_offset(idx)) with UniqueID(hook.unique_id): with hook_meta_ctx, startctx: print_hook_start_line(hook_text, idx, num_hooks) status = 'OK' with Timer() as timer: if len(sql.strip()) > 0: status, _ = adapter.execute(sql, auto_begin=False, fetch=False) self.ran_hooks.append(hook) with finishctx, DbtModelState({'node_status': 'passed'}): print_hook_end_line(hook_text, status, idx, num_hooks, timer.elapsed) self._total_executed += len(ordered_hooks) with TextOnly(): print_timestamped_line("")