|
8 | 8 | from collections.abc import Generator, Mapping, Sequence
|
9 | 9 | from concurrent.futures import Future, ThreadPoolExecutor
|
10 | 10 | from contextlib import AbstractContextManager, ExitStack
|
11 |
| -from typing import TYPE_CHECKING, NamedTuple, Optional, Union, cast |
| 11 | +from typing import TYPE_CHECKING, Callable, NamedTuple, Optional, Union, cast |
12 | 12 |
|
13 | 13 | from typing_extensions import Self
|
14 | 14 |
|
|
49 | 49 | from dagster._daemon.daemon import DaemonIterator
|
50 | 50 |
|
51 | 51 |
|
| 52 | +# scheduler_id, next_iteration_timestamp, now |
| 53 | +SchedulerDelayInstrumentation = Callable[[str, float, float], None] |
| 54 | + |
| 55 | + |
| 56 | +def default_scheduler_delay_instrumentation( |
| 57 | + scheduler_id: str, next_iteration_timestamp: float, now_timestamp: float |
| 58 | +) -> None: |
| 59 | + pass |
| 60 | + |
| 61 | + |
52 | 62 | # how often do we update the job row in the database with the last iteration timestamp. This
|
53 | 63 | # creates a checkpoint so that if the cron schedule changes, we don't try to backfill schedule ticks
|
54 | 64 | # from the start of the schedule, just since the last recorded iteration interval.
|
@@ -189,6 +199,7 @@ def execute_scheduler_iteration_loop(
|
189 | 199 | max_catchup_runs: int,
|
190 | 200 | max_tick_retries: int,
|
191 | 201 | shutdown_event: threading.Event,
|
| 202 | + scheduler_delay_instrumentation: SchedulerDelayInstrumentation = default_scheduler_delay_instrumentation, |
192 | 203 | ) -> "DaemonIterator":
|
193 | 204 | from dagster._daemon.daemon import SpanMarker
|
194 | 205 |
|
@@ -235,6 +246,7 @@ def execute_scheduler_iteration_loop(
|
235 | 246 | scheduler_run_futures=scheduler_run_futures,
|
236 | 247 | max_catchup_runs=max_catchup_runs,
|
237 | 248 | max_tick_retries=max_tick_retries,
|
| 249 | + scheduler_delay_instrumentation=scheduler_delay_instrumentation, |
238 | 250 | )
|
239 | 251 | except Exception:
|
240 | 252 | error_info = DaemonErrorCapture.process_exception(
|
@@ -267,6 +279,7 @@ def launch_scheduled_runs(
|
267 | 279 | max_catchup_runs: int = DEFAULT_MAX_CATCHUP_RUNS,
|
268 | 280 | max_tick_retries: int = 0,
|
269 | 281 | debug_crash_flags: Optional[DebugCrashFlags] = None,
|
| 282 | + scheduler_delay_instrumentation: SchedulerDelayInstrumentation = default_scheduler_delay_instrumentation, |
270 | 283 | ) -> "DaemonIterator":
|
271 | 284 | instance = workspace_process_context.instance
|
272 | 285 |
|
@@ -412,6 +425,13 @@ def launch_scheduled_runs(
|
412 | 425 | # Not enough time has passed for this schedule, don't bother creating a thread
|
413 | 426 | continue
|
414 | 427 |
|
| 428 | + if previous_iteration_times: |
| 429 | + scheduler_delay_instrumentation( |
| 430 | + schedule.selector_id, |
| 431 | + previous_iteration_times.next_iteration_timestamp, |
| 432 | + now_timestamp, |
| 433 | + ) |
| 434 | + |
415 | 435 | future = threadpool_executor.submit(
|
416 | 436 | launch_scheduled_runs_for_schedule,
|
417 | 437 | workspace_process_context,
|
|
0 commit comments