So we've deployed our Meltano docker image to GAE ...
# announcements
m
So we've deployed our Meltano docker image to GAE and we're getting these errors from Airflow:
Copy code
airflow.exceptions.AirflowException: dag_id could not be found: meltano_gmail-to-snowflake. Either the dag did not exist or it failed to parse.
at
get_dag (/projects/.meltano/orchestrators/airflow/venv/lib/python3.8/site-packages/airflow/bin/cli.py:162)
at
run (/projects/.meltano/orchestrators/airflow/venv/lib/python3.8/site-packages/airflow/bin/cli.py:538)
at
wrapper (/projects/.meltano/orchestrators/airflow/venv/lib/python3.8/site-packages/airflow/utils/cli.py:76)
at
<module> (/projects/.meltano/orchestrators/airflow/venv/bin/airflow:37)
Copy code
airflow.exceptions.AirflowTaskTimeout: Timeout, PID: 51
at
handle_timeout (/projects/.meltano/orchestrators/airflow/venv/lib/python3.8/site-packages/airflow/utils/timeout.py:43)
at
communicate (/usr/local/lib/python3.8/subprocess.py:1011)
at
run (/usr/local/lib/python3.8/subprocess.py:491)
at
<module> (/projects/orchestrate/dags/meltano.py:43)
at
_call_with_frames_removed (<frozen importlib._bootstrap>:219)
at
exec_module (<frozen importlib._bootstrap_external>:783)
at
_load_unlocked (<frozen importlib._bootstrap>:671)
at
_load (<frozen importlib._bootstrap>:702)
at
load_source (/usr/local/lib/python3.8/imp.py:171)
at
process_file (/projects/.meltano/orchestrators/airflow/venv/lib/python3.8/site-packages/airflow/models/dagbag.py:256)
Are these normal errors?
d
Are these normal errors?
Definitely not! What exact command are you running? Does
meltano invoke airflow scheduler
show the
meltano_gmail-to-snowflake
DAG being created? Does it show up in the UI?
m
We're just running the
meltano invoke airflow scheduler
as our entrypoint for the container. These are the logs we're getting from the container. It looks like it's constantly restarting the scheduler.
d
You're right, it looks like it gets to
[2020-12-01 17:24:18,269] {sequential_executor.py:54} INFO - Executing command: ['airflow', 'run', 'meltano_gmail-to-snowflake', 'extract_load', '2020-11-30T00:00:00+00:00', '--local', '--pool', 'default_pool', '-sd', '/projects/orchestrate/dags/meltano.py']
, then that fails because of
airflow.exceptions.AirflowException: dag_id could not be found: meltano_gmail-to-snowflake. Either the dag did not exist or it failed to parse.
, and then the scheduler restarts
Can you share your
/projects/orchestrate/dags/meltano.py
? That second error your shared suggests that it may be timing out on
subprocess.run
on line 43
The default timeout for the entirety of importing and running
orchestrate/dags/meltano.py
appears to be 30s: https://github.com/apache/airflow/blob/4f4714fa33947657229d17cf2e2d938771ceca9b/airflow/config_templates/default_airflow.cfg#L150
meltano schedule list --format=json
takes just a few seconds for me in a local project, but can you see if it's slower for you?
It also wouldn't hurt to review https://meltano.com/docs/production.html#airflow-orchestrator and make sure you're following Airflow's production best practices
m
We didn't change anything with airflow, but here's the
airflow.py
Copy code
# This file is managed by the 'airflow' file bundle and updated automatically when `meltano upgrade` is run.
# To prevent any manual changes from being overwritten, remove the file bundle from `meltano.yml` or disable automatic updates:
#     meltano config --plugin-type=files airflow set _update orchestrate/dags/meltano.py false

# If you want to define a custom DAG, create
# a new file under orchestrate/dags/ and Airflow
# will pick it up automatically.

import os
import logging
import subprocess
import json

from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import timedelta
from pathlib import Path


logger = logging.getLogger(__name__)


DEFAULT_ARGS = {
    "owner": "airflow",
    "depends_on_past": False,
    "email_on_failure": False,
    "email_on_retry": False,
    "catchup": False,
    "retries": 1,
    "retry_delay": timedelta(minutes=5),
    "concurrency": 1,
}

project_root = os.getenv("MELTANO_PROJECT_ROOT", os.getcwd())

meltano_bin = ".meltano/run/bin"

if not Path(project_root).joinpath(meltano_bin).exists():
    logger.warning(f"A symlink to the 'meltano' executable could not be found at '{meltano_bin}'. Falling back on expecting it to be in the PATH instead.")
    meltano_bin = "meltano"


result = subprocess.run(
    [meltano_bin, "schedule", "list", "--format=json"],
    cwd=project_root,
    stdout=subprocess.PIPE,
    universal_newlines=True,
    check=True,
)
schedules = json.loads(result.stdout)

for schedule in schedules:
    <http://logger.info|logger.info>(f"Considering schedule '{schedule['name']}': {schedule}")

    if not schedule["cron_interval"]:
        <http://logger.info|logger.info>(
            f"No DAG created for schedule '{schedule['name']}' because its interval is set to `@once`."
        )
        continue

    args = DEFAULT_ARGS.copy()
    if schedule["start_date"]:
        args["start_date"] = schedule["start_date"]

    dag_id = f"meltano_{schedule['name']}"

    # from <https://airflow.apache.org/docs/stable/scheduler.html#backfill-and-catchup>
    #
    # It is crucial to set `catchup` to False so that Airflow only create a single job
    # at the tail end of date window we want to extract data.
    #
    # Because our extractors do not support date-window extraction, it serves no
    # purpose to enqueue date-chunked jobs for complete extraction window.
    dag = DAG(
        dag_id, catchup=False, default_args=args, schedule_interval=schedule["interval"], max_active_runs=1
    )

    elt = BashOperator(
        task_id="extract_load",
        bash_command=f"cd {project_root}; {meltano_bin} elt {' '.join(schedule['elt_args'])}",
        dag=dag,
        env={
            # inherit the current env
            **os.environ,
            **schedule["env"],
        },
    )

    # register the dag
    globals()[dag_id] = dag

    <http://logger.info|logger.info>(f"DAG created for schedule '{schedule['name']}'")
Locally it runs fine too.
d
Can you verify that increasing the timeout (https://airflow.apache.org/docs/stable/configurations-ref.html#dagbag-import-timeout) fixes things?
meltano config airflow set core dagbag_import_timeout 120
should work, or you can
export AIRFLOW__CORE__DAGBAG_IMPORT_TIMEOUT=120
What Airflow version are you using?
If you run
meltano schedule list --format=json
directly in the container, does it take more than 30s?
m
Airflow version:
1.10.12
(The default) Docker image based on
meltano/meltano:latest-python3.8
meltano schedule list --format=json
returns (nearly) instantaneously locally.
d
All right
What are the differences between your local and production environments? Same Docker container I assume, but I assume you're using different system databases, for example? That could have an impact on
meltano schedule list --format=json
load time, but still shouldn't cause it to time out. Perhaps the issue is with concurrent connections to the database, if multiple
meltano
s are running simultaneously (
meltano invoke airflow scheduler
+
meltano schedule list
inside
dags/meltano.py
+
meltano schedule list
inside each
airflow run
(which is the one we're seeing time out) +
meltano elt
for each pipeline).
If you're storing Airflow's metadata database in the DB, that would add to the connections as well
If it stops accepting connections, I'd expect the next
meltano
process to just die with an error instead of time out, but who knows