You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@alexakra This issue need more information. What do you mean by no scheduling? Is it that dagruns are not created at all? Please explain with more information
What do you mean by no scheduling? Is it that dagruns are not created at all?
There is a record in the "dag" table in which next_dagrun_create_after remains null.
In the description above, I pointed to the exact line in the code. It was changed in 2.2.
And "If this condition is evaluated when a state is "running" then it is incorrect.", i.e. condition should be ">" instead of ">=".
When next_dagrun_create_after remains null, the dag doesn't run/scheduled anymore.
What do you mean by no scheduling? Is it that dagruns are not created at all?
There is a record in the "dag" table in which next_dagrun_create_after remains null. In the description above, I pointed to the exact line in the code. It was changed in 2.2. And "If this condition is evaluated when a state is "running" then it is incorrect.", i.e. condition should be ">" instead of ">=". When next_dagrun_create_after remains null, the dag doesn't run/scheduled anymore.
max_active_runs is for dag_runs in running state. Do you mean that when you set max_active_runs=1 in your DAG that you don't see any dagruns in running state? I'm trying to understand your issue. What is the issue? Not asking for the code explanation but the issue you face when you use max_active_runs in your dag
Yes, when I set max_active_runs=1 in a DAG, I don't see any dagruns in running state. It is not triggered anymore after it ran only once.
This looks like an issue with your schedule interval and not max_active_runs because I have a dag with max_active_runs=1 that is running correctly with airflow 2.2.2.
Can you share your DAG file
I think I'm experiencing a similar circumstance (on 2.2.2), however I usually get more than one run after causing a re-process.
It's not specific to any particular DAG, but there is some kind of condition (that I can't replicate on-demand) which results in the scheduler no longer creating new DAGruns. It always happens with DAGs whose max_active_runs is easy to hit, in the 1-3 range. IIRC every time I've seen this, the column DAG.next_dagrun_create_after is empty for that DAG -- but not every DAG that has this field empty has this issue. Another correlated symptom is that affected DAGs no longer get any scheduler/processing logs (in $AIRFLOW_HOME/logs/scheduler/<DATE>/...).
This happens to me maybe 2-3 times a month and I have all my (INFO) scheduler logs, although I haven't seen any anomalies myself. If anyone with better insight on the scheduler's state machine can tell me what to look for in the logs I can search deeper. Or I can even add some log points on my installation to collect until the anomaly occurs again.
@alexakra do your blocked DAGs have processing logs in the above path? And just wondering, what's your setting for schedule_after_task_execution?
I didn't notice whether the processing logs were created or not.
I have just looked for "Setting next_dagrun for %s to %s" in the logs and it was missing. This is the reason I assumed that the condition that I mentioned in the description is True, i.e. orm_dag.next_dagrun_create_after = None.
I have dozens of scheduled DAGs and this happened for all of them immediately after upgrade to 2.2.2. So, I reverted back to 2.1.4.
This issue has been automatically marked as stale because it has been open for 30 days with no response from the author. It will be closed in next 7 days if no further activity occurs from the issue author.
@easontm@alexakra
Hello. I'm also experiencing a similar situation closer to @easontm, where the scheduler does not schedule a DAG in Airflow 2.2.3.
I have a "DAG for health check" of which schedule_interval is */10 * * * * (runs every ten minutes). And almost every specific time(02:20), this dag is not scheduled and column DAG.next_dagrun_create_after is NULL.
After a few minutes later (ex. 02:25~30), the dag is scheduled only then. So there is a delay in dag scheduling. ( airflow_dagrun_schedule_delay metric is below)
I think it happens because many tasks are running and scheduled at 02:20, but they work(run or scheduled) well except "health check DAG".
Another correlated symptom is that affected DAGs no longer get any scheduler/processing logs (in $AIRFLOW_HOME/logs/scheduler//...).
Also there is no scheduler log about affected DAG same as @easontm.
Is there any other workaround or solution without downgrade?
Thank you in advance :)
@holyachon I have created a truly horrifying script to prevent this from occurring. I actually bundled it with some scheduling delay measurement I was trying to do, because when a DAGrun isn't created the built-in schedule delay metric isn't accurate.
The tl;dr is I look at all active DAGs, look at the latest DAG run, and use the schedule to determine if there should be a DAGrun between the latest and now. If I detect a delay, I touch the file which forces the dagprocessor to reexamine the file. I run this on an independent pod in my deployment. Just take out all the statsd stuff if you don't want measurement. And adapt the connection for whatever backend DB you're using.
I previously just tried to touch all DAG files (in small batches spread over a couple hours), but that actually made things worse. So I have this slightly more surgical application.
code
importsubprocessimportsysimporttracebackfromdatetimeimportdatetime, timedeltafromjsonimportloadsfromosimportenviron, pathfrompathlibimportPathfrompprintimportpformatfromtimeimportsleepfrommysql.connectorimportconnectionfromstatsdimportStatsClientsubprocess.check_call([sys.executable, "-m", "pip", "install", "croniter"])
statsd=StatsClient("airflow-scheduler", 9125)
SLEEP_TIME=60SQL_ALCHEMY_CONN=environ["SQL_ALCHEMY_CONN"]
user=SQL_ALCHEMY_CONN.split("://")[1].split(":")[0]
password=SQL_ALCHEMY_CONN.split("/"+user+":")[1].split("@")[0]
host=SQL_ALCHEMY_CONN.split("@")[1].split(":3306/")[0]
database=SQL_ALCHEMY_CONN.split(":3306/")[1]
defprocess_dag(dag, check_time):
fromcroniterimportcroniterexec_date=dag["execution_date"]
end_date=dag["end_date"]
mar=dag["max_active_runs"]
schedule_interval=dag["schedule_interval"]
dag_id=dag["dag_id"]
state=dag["state"]
ifexec_dateisNone:
print(f"[WARN] No run found for {dag_id} in the last 10 days.")
returnifschedule_interval[0] =="{":
j=loads(schedule_interval)
td=timedelta(
days=j["attrs"]["days"],
seconds=j["attrs"]["seconds"],
microseconds=j["attrs"]["microseconds"],
)
current_theoretical_start=exec_date+tdnext_theoretical_start=exec_date+td+tdelse:
try:
cron=croniter(schedule_interval, exec_date)
exceptException:
raiseException(
f"Cron gen failed: {dag_id}. schedule interval is {schedule_interval}"
)
current_theoretical_start=cron.get_next(datetime)
next_theoretical_start=cron.get_next(datetime)
try:
ifstate=="running":
# This gets its own case because a running DAG could either be in a backfill# or part of a regular run. That is, next_theoretical_start may be before# OR after check_time, and we can't use that switch by itself.# if we are evaluating a running DAGrun we will measure the best between# 1. difference between previous end and this start# a. If this is negative (overlapping runs) we will use 0# 2. the difference between the actual and scheduled startreturn0elif (
next_theoretical_start<check_time
): # if the next one should have started already# It's possible that a DAGrun didn't start because we reached peak concurrency for# some time. While this can happen for any MAR value, 1 is the most dangerous one# for natural reasons. In case the previous DAG took a long time, we will take the# delta between the previous ending and the current check time. This can probably# be refined in the future.ifmar==1:
returnmin(
(check_time-next_theoretical_start).total_seconds(),
(check_time-end_date).total_seconds(),
)
else:
return (check_time-next_theoretical_start).total_seconds()
else:
# We will consider DAGs whose runs are caught up to not be in a delay state# even if the previous run was delayed, because this will make the metric# represent the current state of the system. Any delays will be present in# the historical values.return0exceptExceptionase:
print(f"Error processing DAG {dag}")
print(f"current_theoretical_start: {current_theoretical_start}")
print(f"next_theoretical_start: {next_theoretical_start}")
print(f"check_time: {check_time}")
print(traceback.format_exc())
print(e)
whileTrue:
now=datetime.now()
print(f"Starting check: {now}")
withconnection.MySQLConnection( # mysql.connector.connect(host=host, user=user, password=password, database=database,
) asmydb:
withmydb.cursor() ascur:
query=f""" SELECT dag.dag_id ,fileloc ,schedule_interval ,max_active_runs ,state ,execution_date ,start_date ,end_date ,gap FROM dag LEFT JOIN ( SELECT dag_id ,execution_date ,start_date ,end_date ,state ,RANK() OVER (PARTITION BY dag_id ORDER BY execution_date DESC) AS rnk ,TIMEDIFF( start_date, LAG(end_date) OVER (PARTITION BY dag_id ORDER BY execution_date ASC) ) AS gap FROM dag_run WHERE DATE(start_date) >= DATE'{str(now-timedelta(days=10))[:10]}' AND run_id NOT LIKE 'manual%' ) runs ON dag.dag_id = runs.dag_id WHERE NOT is_paused AND is_active AND NOT is_subdag AND schedule_interval <> 'null' AND schedule_interval <> '"@once"' AND (rnk = 1 OR rnk IS NULL) -- AND state <> 'running' """print(f"Executing query: \n{query}")
cur.execute(query)
col_names= [i[0] foriincur.description]
results=cur.fetchall()
r_maps= [
{
col_names[i]: r[i] iftype(r[i]) !=strelser[i].strip('"')
foriinrange(len(col_names))
}
forrinresults
]
touched= []
delayed= []
total_delay=0fordaginr_maps:
delay=process_dag(dag, now)
ifdelayisNone:
continueifdelay>600:
delayed.append((dag["dag_id"], round(delay)))
ifnow.timestamp() -path.getmtime(dag["fileloc"]) >delay:
Path(dag["fileloc"]).touch()
touched.append((dag["dag_id"], round(delay)))
total_delay+=delayprint(f"DAG: {dag['dag_id']} -- delay: {round(delay, 2)}")
statsd.gauge(f"airflow.custom_dag_delay.{dag['dag_id']}", delay)
avg_delay=round(total_delay/len(r_maps))
# statsd.gauge(f"airflow.custom_dag_delay_avg.{avg_delay}", delay)print(f"Delayed DAGs: {pformat(delayed)}")
print(f"Touched DAGs: {pformat(touched)}")
print(
f"Total delay: {round(total_delay)}s across {len(r_maps)} DAGs. {avg_delay}s per DAG"
)
print(f"End loop. Sleeping for {SLEEP_TIME} seconds.")
sleep(SLEEP_TIME)
Activity
easontm commentedon Dec 8, 2021
Just out of curiosity, does the scheduler create another run if you modify the file?
ephraimbuddy commentedon Dec 8, 2021
@alexakra This issue need more information. What do you mean by no scheduling? Is it that dagruns are not created at all? Please explain with more information
alexakra commentedon Dec 9, 2021
yes, just another single run
alexakra commentedon Dec 9, 2021
There is a record in the "dag" table in which
next_dagrun_create_afterremainsnull.In the description above, I pointed to the exact line in the code. It was changed in 2.2.
And "If this condition is evaluated when a state is "running" then it is incorrect.", i.e. condition should be ">" instead of ">=".
When
next_dagrun_create_afterremainsnull, the dag doesn't run/scheduled anymore.ephraimbuddy commentedon Dec 9, 2021
max_active_runs is for dag_runs in
runningstate. Do you mean that when you setmax_active_runs=1in your DAG that you don't see any dagruns inrunningstate? I'm trying to understand your issue. What is the issue? Not asking for the code explanation but the issue you face when you usemax_active_runsin your dagalexakra commentedon Dec 9, 2021
Yes, when I set
max_active_runs=1in a DAG, I don't see any dagruns in running state. It is not triggered anymore after it ran only once.ephraimbuddy commentedon Dec 9, 2021
This looks like an issue with your schedule interval and not max_active_runs because I have a dag with max_active_runs=1 that is running correctly with airflow 2.2.2.
Can you share your DAG file
alexakra commentedon Dec 9, 2021
test_dag.py.txt
ephraimbuddy commentedon Dec 9, 2021
I ran your dag and it ran perfectly well
alexakra commentedon Dec 9, 2021
Could it be related to an upgraded from 2.1.4?
ephraimbuddy commentedon Dec 9, 2021
Not sure but check your logs if there's anything you can see
easontm commentedon Dec 19, 2021
I think I'm experiencing a similar circumstance (on 2.2.2), however I usually get more than one run after causing a re-process.
It's not specific to any particular DAG, but there is some kind of condition (that I can't replicate on-demand) which results in the scheduler no longer creating new DAGruns. It always happens with DAGs whose
max_active_runsis easy to hit, in the 1-3 range. IIRC every time I've seen this, the columnDAG.next_dagrun_create_afteris empty for that DAG -- but not every DAG that has this field empty has this issue. Another correlated symptom is that affected DAGs no longer get any scheduler/processing logs (in$AIRFLOW_HOME/logs/scheduler/<DATE>/...).This happens to me maybe 2-3 times a month and I have all my (
INFO) scheduler logs, although I haven't seen any anomalies myself. If anyone with better insight on the scheduler's state machine can tell me what to look for in the logs I can search deeper. Or I can even add some log points on my installation to collect until the anomaly occurs again.@alexakra do your blocked DAGs have processing logs in the above path? And just wondering, what's your setting for
schedule_after_task_execution?alexakra commentedon Dec 19, 2021
I didn't notice whether the processing logs were created or not.
I have just looked for "Setting next_dagrun for %s to %s" in the logs and it was missing. This is the reason I assumed that the condition that I mentioned in the description is True, i.e.
orm_dag.next_dagrun_create_after = None.I have dozens of scheduled DAGs and this happened for all of them immediately after upgrade to 2.2.2. So, I reverted back to 2.1.4.
github-actions commentedon Jan 19, 2022
This issue has been automatically marked as stale because it has been open for 30 days with no response from the author. It will be closed in next 7 days if no further activity occurs from the issue author.
github-actions commentedon Jan 26, 2022
This issue has been closed because it has not received response from the issue author.
holyachon commentedon Feb 4, 2022
@easontm @alexakra

Hello. I'm also experiencing a similar situation closer to @easontm, where the scheduler does not schedule a DAG in Airflow 2.2.3.
I have a "DAG for health check" of which schedule_interval is
*/10 * * * *(runs every ten minutes). And almost every specific time(02:20), this dag is not scheduled and columnDAG.next_dagrun_create_afteris NULL.After a few minutes later (ex. 02:25~30), the dag is scheduled only then. So there is a delay in dag scheduling. (
airflow_dagrun_schedule_delaymetric is below)I think it happens because many tasks are running and scheduled at 02:20, but they work(run or scheduled) well except "health check DAG".
Also there is no scheduler log about affected DAG same as @easontm.
Is there any other workaround or solution without downgrade?
Thank you in advance :)
easontm commentedon Feb 7, 2022
@holyachon I have created a truly horrifying script to prevent this from occurring. I actually bundled it with some scheduling delay measurement I was trying to do, because when a DAGrun isn't created the built-in schedule delay metric isn't accurate.
The tl;dr is I look at all active DAGs, look at the latest DAG run, and use the schedule to determine if there should be a DAGrun between the latest and now. If I detect a delay, I touch the file which forces the dagprocessor to reexamine the file. I run this on an independent pod in my deployment. Just take out all the statsd stuff if you don't want measurement. And adapt the connection for whatever backend DB you're using.
I previously just tried to touch all DAG files (in small batches spread over a couple hours), but that actually made things worse. So I have this slightly more surgical application.
code
holyachon commentedon Feb 7, 2022
@easontm Thank you for your reply :)
I think I don't have the confidence to manage that DAG well..
Fortunately, the airflow's bug related the problem in this issue was found.
Therefore, after #21214 PR is merged, we can all be happy 😄
Thanks again for sharing your idea!