|
20 | 20 | import logging |
21 | 21 | import os |
22 | 22 | import signal |
| 23 | +import socket |
23 | 24 | import subprocess |
24 | 25 | import time |
25 | 26 |
|
|
52 | 53 | log = logging.getLogger("integration.otel.test_otel") |
53 | 54 |
|
54 | 55 |
|
| 56 | +def wait_for_otel_collector(host: str, port: int, timeout: int = 120) -> None: |
| 57 | + """ |
| 58 | + Wait for the OTel collector to be reachable before running tests. |
| 59 | +
|
| 60 | + This prevents flaky test failures caused by transient DNS resolution issues |
| 61 | + (e.g., 'Temporary failure in name resolution' for breeze-otel-collector). |
| 62 | +
|
| 63 | + Note: If the collector is not reachable after timeout, logs a warning but |
| 64 | + does not fail - allows tests to run and fail naturally if needed. |
| 65 | + """ |
| 66 | + deadline = time.monotonic() + timeout |
| 67 | + last_error = None |
| 68 | + while time.monotonic() < deadline: |
| 69 | + try: |
| 70 | + # Test DNS resolution and TCP connectivity |
| 71 | + with socket.create_connection((host, port), timeout=5): |
| 72 | + pass |
| 73 | + log.info("OTel collector at %s:%d is reachable.", host, port) |
| 74 | + return |
| 75 | + except (socket.gaierror, TimeoutError, OSError) as e: |
| 76 | + last_error = e |
| 77 | + log.debug( |
| 78 | + "OTel collector at %s:%d not reachable: %s. Retrying...", |
| 79 | + host, |
| 80 | + port, |
| 81 | + e, |
| 82 | + ) |
| 83 | + time.sleep(2) |
| 84 | + log.warning( |
| 85 | + "OTel collector at %s:%d is not reachable after %ds. Last error: %s. " |
| 86 | + "Tests will proceed but may fail if collector is required.", |
| 87 | + host, |
| 88 | + port, |
| 89 | + timeout, |
| 90 | + last_error, |
| 91 | + ) |
| 92 | + |
| 93 | + |
55 | 94 | def unpause_trigger_dag_and_get_run_id(dag_id: str) -> str: |
56 | 95 | unpause_command = ["airflow", "dags", "unpause", dag_id] |
57 | 96 |
|
@@ -611,9 +650,17 @@ class TestOtelIntegration: |
611 | 650 |
|
612 | 651 | @classmethod |
613 | 652 | def setup_class(cls): |
| 653 | + otel_host = "breeze-otel-collector" |
| 654 | + otel_port = 4318 |
| 655 | + |
| 656 | + # Wait for OTel collector to be reachable before running tests. |
| 657 | + # This prevents flaky test failures caused by transient DNS resolution issues |
| 658 | + # during scheduler handoff (see https://github.com/apache/airflow/issues/61070). |
| 659 | + wait_for_otel_collector(otel_host, otel_port) |
| 660 | + |
614 | 661 | os.environ["AIRFLOW__TRACES__OTEL_ON"] = "True" |
615 | | - os.environ["AIRFLOW__TRACES__OTEL_HOST"] = "breeze-otel-collector" |
616 | | - os.environ["AIRFLOW__TRACES__OTEL_PORT"] = "4318" |
| 662 | + os.environ["AIRFLOW__TRACES__OTEL_HOST"] = otel_host |
| 663 | + os.environ["AIRFLOW__TRACES__OTEL_PORT"] = str(otel_port) |
617 | 664 | if cls.use_otel != "true": |
618 | 665 | os.environ["AIRFLOW__TRACES__OTEL_DEBUGGING_ON"] = "True" |
619 | 666 |
|
|
0 commit comments