Ejemplo n.º 1
0
def test_execute_schedule_on_celery_k8s(  # pylint: disable=redefined-outer-name, disable=unused-argument
        dagster_instance_for_daemon, helm_namespace_for_daemon):
    schedule_name = "frequent_celery"
    with get_test_project_external_schedule(
            dagster_instance_for_daemon, schedule_name) as external_schedule:
        reoriginated_schedule = ReOriginatedExternalScheduleForTest(
            external_schedule)
        dagster_instance_for_daemon.start_schedule(reoriginated_schedule)

        scheduler_runs = dagster_instance_for_daemon.get_runs(
            RunsFilter(
                tags=PipelineRun.tags_for_schedule(reoriginated_schedule)))

        assert len(scheduler_runs) == 0

        try:

            start_time = time.time()

            while True:
                schedule_runs = dagster_instance_for_daemon.get_runs(
                    RunsFilter(tags=PipelineRun.tags_for_schedule(
                        reoriginated_schedule)))

                if len(schedule_runs) > 0:
                    break

                if time.time() - start_time > 120:
                    raise Exception(
                        "Timed out waiting for schedule to start a run. "
                        "Check the dagster-daemon pod logs to see why it didn't start."
                    )

                time.sleep(1)
                continue

        finally:
            dagster_instance_for_daemon.stop_schedule(
                reoriginated_schedule.get_external_origin_id(),
                reoriginated_schedule.selector_id,
                reoriginated_schedule,
            )

        last_run = schedule_runs[0]

        finished_pipeline_run = poll_for_finished_run(
            dagster_instance_for_daemon, last_run.run_id, timeout=120)

        assert finished_pipeline_run.is_success
Ejemplo n.º 2
0
def test_queue_from_schedule_and_sensor(instance, foo_example_workspace, foo_example_repo):
    external_schedule = foo_example_repo.get_external_schedule("always_run_schedule")
    external_sensor = foo_example_repo.get_external_sensor("always_on_sensor")
    external_pipeline = foo_example_repo.get_full_external_pipeline("foo_pipeline")

    instance.start_schedule_and_update_storage_state(external_schedule)
    instance.start_sensor(external_sensor)

    with start_daemon(timeout=180):
        run = create_run(instance, external_pipeline)
        instance.submit_run(run.run_id, foo_example_workspace)

        runs = [
            poll_for_finished_run(instance, run.run_id),
            poll_for_finished_run(instance, run_tags=PipelineRun.tags_for_sensor(external_sensor)),
            poll_for_finished_run(
                instance,
                run_tags=PipelineRun.tags_for_schedule(external_schedule),
                timeout=90,
            ),
        ]

        for run in runs:
            logs = instance.all_logs(run.run_id)
            assert_events_in_order(
                logs,
                [
                    "PIPELINE_ENQUEUED",
                    "PIPELINE_DEQUEUED",
                    "PIPELINE_STARTING",
                    "PIPELINE_START",
                    "PIPELINE_SUCCESS",
                ],
            )
Ejemplo n.º 3
0
    def get_execution_data(
        self, context: "ScheduleExecutionContext"
    ) -> List[Union[RunRequest, SkipReason]]:
        check.inst_param(context, "context", ScheduleExecutionContext)
        execution_fn = cast(Callable[[ScheduleExecutionContext], Any],
                            self._execution_fn)
        result = list(ensure_gen(execution_fn(context)))

        if not result:
            return []

        if len(result) == 1:
            check.is_list(result, of_type=(RunRequest, SkipReason))
            data = result[0]

            if isinstance(data, SkipReason):
                return result
            check.inst(data, RunRequest)
            return [
                RunRequest(
                    run_key=data.run_key,
                    run_config=data.run_config,
                    tags=merge_dicts(data.tags,
                                     PipelineRun.tags_for_schedule(self)),
                )
            ]

        check.is_list(result, of_type=RunRequest)

        check.invariant(
            not any(not data.run_key for data in result),
            "Schedules that return multiple RunRequests must specify a run_key in each RunRequest",
        )

        # clone all the run requests with the required schedule tags
        return [
            RunRequest(
                run_key=data.run_key,
                run_config=data.run_config,
                tags=merge_dicts(data.tags,
                                 PipelineRun.tags_for_schedule(self)),
            ) for data in result
        ]
Ejemplo n.º 4
0
    def get_tags(self, context):
        check.inst_param(context, "context", ScheduleExecutionContext)
        if self._tags:
            tags = self._tags
            check_tags(tags, "tags")
        else:
            tags = self._tags_fn(context)
            # These tags are checked in _tags_fn_wrapper

        tags = merge_dicts(tags, PipelineRun.tags_for_schedule(self))

        return tags
Ejemplo n.º 5
0
def _get_existing_run_for_request(instance, external_schedule, schedule_time, run_request):
    tags = merge_dicts(
        PipelineRun.tags_for_schedule(external_schedule),
        {SCHEDULED_EXECUTION_TIME_TAG: schedule_time.in_tz("UTC").isoformat(),},
    )
    if run_request.run_key:
        tags[RUN_KEY_TAG] = run_request.run_key
    runs_filter = PipelineRunsFilter(tags=tags)
    existing_runs = instance.get_runs(runs_filter)
    if not len(existing_runs):
        return None
    return existing_runs[0]
Ejemplo n.º 6
0
def test_queue_from_schedule_and_sensor(tmpdir, foo_example_repo):
    dagster_home_path = tmpdir.strpath
    with setup_instance(
            dagster_home_path,
            """run_coordinator:
    module: dagster.core.run_coordinator
    class: QueuedRunCoordinator
    config:
        dequeue_interval_seconds: 1
    """,
    ) as instance:
        external_schedule = foo_example_repo.get_external_schedule(
            "never_run_schedule")
        external_sensor = foo_example_repo.get_external_sensor(
            "never_on_sensor")

        foo_pipeline_handle = PipelineHandle("foo_pipeline",
                                             foo_example_repo.handle)

        instance.start_schedule_and_update_storage_state(external_schedule)
        instance.start_sensor(external_sensor)

        with start_daemon(timeout=180):
            run = create_run(instance, foo_pipeline_handle)
            with external_pipeline_from_run(run) as external_pipeline:
                instance.submit_run(run.run_id, external_pipeline)

                runs = [
                    poll_for_finished_run(instance, run.run_id),
                    poll_for_finished_run(
                        instance,
                        run_tags=PipelineRun.tags_for_sensor(external_sensor)),
                    poll_for_finished_run(
                        instance,
                        run_tags=PipelineRun.tags_for_schedule(
                            external_schedule),
                        timeout=90,
                    ),
                ]

                for run in runs:
                    logs = instance.all_logs(run.run_id)
                    assert_events_in_order(
                        logs,
                        [
                            "PIPELINE_ENQUEUED",
                            "PIPELINE_DEQUEUED",
                            "PIPELINE_STARTING",
                            "PIPELINE_START",
                            "PIPELINE_SUCCESS",
                        ],
                    )
Ejemplo n.º 7
0
def _schedule_run_at_time(
    instance,
    logger,
    repo_location,
    schedule_state,
    schedule_time_utc,
    tick_holder,
    debug_crash_flags,
):
    schedule_name = schedule_state.name

    repo_dict = repo_location.get_repositories()
    check.invariant(
        len(repo_dict) == 1,
        "Reconstructed repository location should have exactly one repository",
    )
    external_repo = next(iter(repo_dict.values()))

    external_schedule = external_repo.get_external_schedule(schedule_name)

    pipeline_selector = PipelineSelector(
        location_name=repo_location.name,
        repository_name=external_repo.name,
        pipeline_name=external_schedule.pipeline_name,
        solid_selection=external_schedule.solid_selection,
    )

    subset_pipeline_result = repo_location.get_subset_external_pipeline_result(
        pipeline_selector)
    external_pipeline = ExternalPipeline(
        subset_pipeline_result.external_pipeline_data,
        external_repo.handle,
    )

    # Rule out the case where the scheduler crashed between creating a run for this time
    # and launching it
    runs_filter = PipelineRunsFilter(tags=merge_dicts(
        PipelineRun.tags_for_schedule(schedule_state),
        {SCHEDULED_EXECUTION_TIME_TAG: schedule_time_utc.isoformat()},
    ))
    existing_runs = instance.get_runs(runs_filter)

    run_to_launch = None

    if len(existing_runs):
        check.invariant(len(existing_runs) == 1)

        run = existing_runs[0]

        if run.status != PipelineRunStatus.NOT_STARTED:
            # A run already exists and was launched for this time period,
            # but the scheduler must have crashed before the tick could be put
            # into a SUCCESS state

            logger.info(
                "Run {run_id} already completed for this execution of {schedule_name}"
                .format(run_id=run.run_id, schedule_name=schedule_state.name))
            tick_holder.update_with_status(ScheduleTickStatus.SUCCESS,
                                           run_id=run.run_id)

            return
        else:
            logger.info(
                "Run {run_id} already created for this execution of {schedule_name}"
                .format(run_id=run.run_id, schedule_name=schedule_state.name))
            run_to_launch = run
    else:
        run_to_launch = _create_scheduler_run(
            instance,
            logger,
            schedule_time_utc,
            repo_location,
            external_repo,
            external_schedule,
            external_pipeline,
            tick_holder,
        )

        _check_for_debug_crash(debug_crash_flags, "RUN_CREATED")

    if not run_to_launch:
        check.invariant(tick_holder.status != ScheduleTickStatus.STARTED
                        and tick_holder.status != ScheduleTickStatus.SUCCESS)
        return

    if run_to_launch.status != PipelineRunStatus.FAILURE:
        try:
            instance.launch_run(run_to_launch.run_id, external_pipeline)
            logger.info(
                "Completed scheduled launch of run {run_id} for {schedule_name}"
                .format(run_id=run_to_launch.run_id,
                        schedule_name=schedule_name))
        except Exception as e:  # pylint: disable=broad-except
            if not isinstance(e, KeyboardInterrupt):
                error = serializable_error_info_from_exc_info(sys.exc_info())
                instance.report_engine_event(
                    error.message,
                    run_to_launch,
                    EngineEventData.engine_error(error),
                )
                instance.report_run_failed(run_to_launch)
                logger.error(
                    "Run {run_id} created successfully but failed to launch.".
                    format(run_id=run_to_launch.run_id))

    _check_for_debug_crash(debug_crash_flags, "RUN_LAUNCHED")

    tick_holder.update_with_status(ScheduleTickStatus.SUCCESS,
                                   run_id=run_to_launch.run_id)
    _check_for_debug_crash(debug_crash_flags, "TICK_SUCCESS")
Ejemplo n.º 8
0
def _schedule_run_at_time(
    instance,
    logger,
    repo_location,
    external_repo,
    external_schedule,
    schedule_time,
    tick_holder,
    debug_crash_flags,
):
    schedule_name = external_schedule.name

    pipeline_selector = PipelineSelector(
        location_name=repo_location.name,
        repository_name=external_repo.name,
        pipeline_name=external_schedule.pipeline_name,
        solid_selection=external_schedule.solid_selection,
    )

    subset_pipeline_result = repo_location.get_subset_external_pipeline_result(
        pipeline_selector)
    external_pipeline = ExternalPipeline(
        subset_pipeline_result.external_pipeline_data,
        external_repo.handle,
    )

    # Rule out the case where the scheduler crashed between creating a run for this time
    # and launching it
    runs_filter = PipelineRunsFilter(tags=merge_dicts(
        PipelineRun.tags_for_schedule(external_schedule),
        {SCHEDULED_EXECUTION_TIME_TAG: schedule_time.in_tz("UTC").isoformat()},
    ))
    existing_runs = instance.get_runs(runs_filter)

    run_to_launch = None

    if len(existing_runs):
        check.invariant(len(existing_runs) == 1)

        run = existing_runs[0]

        if run.status != PipelineRunStatus.NOT_STARTED:
            # A run already exists and was launched for this time period,
            # but the scheduler must have crashed before the tick could be put
            # into a SUCCESS state

            logger.info(
                "Run {run_id} already completed for this execution of {schedule_name}"
                .format(run_id=run.run_id, schedule_name=schedule_name))
            tick_holder.update_with_status(JobTickStatus.SUCCESS,
                                           run_id=run.run_id)

            return
        else:
            logger.info(
                "Run {run_id} already created for this execution of {schedule_name}"
                .format(run_id=run.run_id, schedule_name=schedule_name))
            run_to_launch = run
    else:
        run_to_launch = _create_scheduler_run(
            instance,
            logger,
            schedule_time,
            repo_location,
            external_repo,
            external_schedule,
            external_pipeline,
            tick_holder,
        )

        _check_for_debug_crash(debug_crash_flags, "RUN_CREATED")

    if not run_to_launch:
        check.invariant(tick_holder.status != JobTickStatus.STARTED
                        and tick_holder.status != JobTickStatus.SUCCESS)
        return

    if run_to_launch.status != PipelineRunStatus.FAILURE:
        try:
            instance.submit_run(run_to_launch.run_id, external_pipeline)
            logger.info(
                "Completed scheduled launch of run {run_id} for {schedule_name}"
                .format(run_id=run_to_launch.run_id,
                        schedule_name=schedule_name))
        except Exception:  # pylint: disable=broad-except
            logger.error(
                "Run {run_id} created successfully but failed to launch.".
                format(run_id=run_to_launch.run_id))

    _check_for_debug_crash(debug_crash_flags, "RUN_LAUNCHED")

    tick_holder.update_with_status(JobTickStatus.SUCCESS,
                                   run_id=run_to_launch.run_id)
    _check_for_debug_crash(debug_crash_flags, "TICK_SUCCESS")
Ejemplo n.º 9
0
 def get_tags(self, context):
     check.inst_param(context, "context", ScheduleExecutionContext)
     tags = self._tags_fn(context)
     return merge_dicts(tags, PipelineRun.tags_for_schedule(self))