Skip to content
RED SAGSkills

Airflow interview questions and answers

Airflow questions test how you build reliable data pipelines: DAG design, scheduling and making tasks safe to retry.

Below are 60 Airflow questions with the correct answer and a short explanation, grouped from fresher to experienced level. Try each one before you open the answer.

What Airflow interviews usually check

  • ✓DAGs, tasks, operators and dependencies
  • ✓Scheduling, data intervals and backfills
  • ✓Idempotent tasks and retries
  • ✓XComs, templating and connections
  • ✓Sensors, pools and executors

Airflow interview questions for freshers easy

1. Priority ceiling protocol

In the priority ceiling protocol, what priority does a task get when it locks a shared resource?

  1. A.The lowest priority that exists in the whole system
  2. B.Its own priority, which does not change at all
  3. C.The highest priority of any task that uses that resource
  4. D.The priority of the idle task plus exactly one level
Show answer

Answer: C. The highest priority of any task that uses that resource

Each resource has a ceiling equal to the highest priority of its users. The locking task runs at that ceiling, so no other user can preempt it while it holds the lock. This bounds blocking and also prevents some deadlocks.

2. Moving notebook code to production

A data scientist’s training notebook works but depends on cells run in a certain order. What is the usual first step to productionise it?

  1. A.Schedule the notebook to run every hour as it is
  2. B.Refactor it into functions or scripts run as pipeline steps
  3. C.Email the notebook to the platform team weekly
  4. D.Convert every cell into a separate microservice
Show answer

Answer: B. Refactor it into functions or scripts run as pipeline steps

Hidden state and manual cell order make notebooks hard to repeat. Moving logic into tested functions with clear inputs and outputs, then wiring them as pipeline steps, gives repeatable, reviewable runs.

3. Attempts with retries=3

A task has retries=3 and fails every time. How many times does Airflow try to run it in total?

  1. A.3
  2. B.4
  3. C.1
  4. D.6
Show answer

Answer: B. 4

retries counts extra attempts after the first one. The task runs once, then up to 3 more times, so 4 attempts in total. After the last failure the task instance is marked failed.

4. Why use an EmptyOperator

A DAG has 20 parallel load tasks and 15 report tasks that should all wait for every load. Why might you put an EmptyOperator between them?

  1. A.It speeds up each of the load tasks
  2. B.It stores all the load results as XCom
  3. C.It gives one join point instead of 300 dependency edges
  4. D.It retries any failed load tasks automatically
Show answer

Answer: C. It gives one join point instead of 300 dependency edges

Without a join, every report depends on every load: 20 × 15 = 300 edges, which clutters the graph. An EmptyOperator does no work; all loads point to it and it points to all reports, giving 35 edges and a clear picture.

5. Finding why a task failed

A task turned red in the grid view. Where do you look first to see the actual error message?

  1. A.The DAG file in the code view
  2. B.The scheduler log on the scheduler machine
  3. C.The pool page in the admin menu
  4. D.The log of that task instance attempt
Show answer

Answer: D. The log of that task instance attempt

Each task instance attempt has its own log with the stack trace or the failing command output, viewable from the task in the UI. Scheduler logs help with scheduling problems, not with errors inside your task code.

6. Where to keep a database password

A DAG needs the host, user and password of the finance Postgres database. Where should these live?

  1. A.Hard-coded at the top of the DAG file
  2. B.In an Airflow Connection or a secrets backend
  3. C.In the task_id of the task that uses them
  4. D.In an XCom pushed by the first task
Show answer

Answer: B. In an Airflow Connection or a secrets backend

An Airflow Connection stores host, login, password and extras under a conn_id that hooks and operators read. The password is encrypted with the Fernet key, or kept in a secrets backend such as Vault or AWS Secrets Manager. Code in Git should never hold the password.

7. Getting the Amazon operators

You need S3 and Redshift operators in a fresh Airflow install. How are they normally added?

  1. A.They are always built into the core package
  2. B.Copy them from GitHub into the DAG folder
  3. C.Install the apache-airflow-providers-amazon package
  4. D.Enable them in the pool settings
Show answer

Answer: C. Install the apache-airflow-providers-amazon package

Integrations ship as separate provider packages, such as apache-airflow-providers-amazon or -google, which are versioned apart from core Airflow. Installing the provider adds its hooks, operators, sensors and connection types.

8. A DAG with a loop in it

A developer writes a >> b and later b >> a in the same DAG. What happens?

  1. A.The tasks run forever in a loop
  2. B.Airflow runs a, then b, then stops
  3. C.The second line silently overrides the first
  4. D.The DAG fails to load with a cycle error
Show answer

Answer: D. The DAG fails to load with a cycle error

A DAG must be acyclic. Airflow detects the cycle when it parses the file and reports an import error, so the DAG does not appear as runnable. Repeating work should be done with schedules or retries, not loops in the graph.

9. default_args and a task that differs

A DAG has default_args={"retries": 2}. One task is created with retries=5. How many retries does that task get?

  1. A.2, because default_args always wins
  2. B.7, because the values add up
  3. C.0, because the two values conflict
  4. D.5, because task arguments override defaults
Show answer

Answer: D. 5, because task arguments override defaults

default_args supplies values for every task in the DAG unless the task sets its own. An argument passed directly to an operator overrides the default, so this task retries up to 5 times and the others up to 2.

10. Starting another DAG at the end

When ingest finishes, it should start the reporting DAG. Which operator does this directly?

  1. A.ExternalTaskSensor
  2. B.EmptyOperator
  3. C.LatestOnlyOperator
  4. D.TriggerDagRunOperator
Show answer

Answer: D. TriggerDagRunOperator

TriggerDagRunOperator creates a run of another DAG, optionally passing conf and waiting for it to finish. ExternalTaskSensor works the other way: the downstream DAG waits for a task in the upstream DAG.

11. The day before ds

For a run with ds = 2026-03-01, what does {{ macros.ds_add(ds, -1) }} render to?

  1. A.2026-03-00
  2. B.2026-02-29
  3. C.2026-02-28
  4. D.2026-03-02
Show answer

Answer: C. 2026-02-28

macros.ds_add adds days to a YYYY-MM-DD string and handles month ends. 2026 is not a leap year, so the day before 1 March is 28 February: 2026-02-28.

12. Stopping Airflow from parsing helpers

The DAG folder also has utils/ and tests/ folders with plain Python files. How do you stop the DAG processor from parsing them?

  1. A.Rename them to end in .txt
  2. B.Mark them as paused in the UI
  3. C.Put them in a pool with no slots
  4. D.List them in a .airflowignore file
Show answer

Answer: D. List them in a .airflowignore file

A .airflowignore file in the DAG folder lists patterns of files and folders the DAG processor should skip. This cuts parse time and avoids import errors from test files.

13. Using a DAG param in SQL

A DAG declares params={"region": "uae"}. How do you use the value inside a templated SQL string?

  1. A.{{ region }}
  2. B.{{ params.region }}
  3. C.${params.region}
  4. D.{{ conf.region }}
Show answer

Answer: B. {{ params.region }}

DAG and task params are available in templates under params, so {{ params.region }} renders "uae" or the value given when the run was triggered. ${...} is not Jinja syntax.

14. Running every 6 hours

Which schedule runs a DAG every 6 hours counted from its start_date?

  1. A.schedule="@hourly" with retries=6
  2. B.schedule="6 * * * *"
  3. C.schedule="@daily" with max_active_runs=4
  4. D.schedule=timedelta(hours=6)
Show answer

Answer: D. schedule=timedelta(hours=6)

A timedelta schedule creates runs at fixed gaps from start_date. "6 * * * *" means minute 6 of every hour, not every 6 hours; the cron for that would be "0 */6 * * *".

15. Triggering a DAG from another system

An upstream app should start an Airflow 3 DAG when its export finishes. What does it call?

  1. A.POST /api/v2/dags/{dag_id}/dagRuns
  2. B.GET /health on the scheduler
  3. C.An INSERT into the dag_run table
  4. D.airflow db migrate over SSH
Show answer

Answer: A. POST /api/v2/dags/{dag_id}/dagRuns

The stable REST API creates a DAG run with a POST to the dagRuns endpoint, optionally with a conf body; Airflow 3 serves it under /api/v2. Writing to the metadata database directly bypasses validation and is not supported.

16. An alert task that fires on failure

A notify_oncall task should run only if any of the 5 load tasks before it fails. Which trigger rule fits?

  1. A.one_failed
  2. B.all_success
  3. C.none_failed
  4. D.all_skipped
Show answer

Answer: A. one_failed

one_failed fires as soon as at least one upstream task has failed, without waiting for the others. If no load fails, notify_oncall is skipped. all_failed would require all five to fail.

17. Key of a returned XCom

A PythonOperator's callable returns 42. Under which XCom key is it stored?

  1. A.result
  2. B.output
  3. C.the task_id
  4. D.return_value
Show answer

Answer: D. return_value

A value returned from an operator's execute (or a Python callable) is pushed as an XCom with key "return_value". xcom_pull(task_ids="t") uses that key by default, so you rarely need to name it.

18. What a @task.bash function returns

With the @task.bash decorator, what should the decorated Python function return?

  1. A.The exit code it expects the script to give
  2. B.A pandas DataFrame for the next task
  3. C.The bash command string to run
  4. D.True when the command has finished
Show answer

Answer: C. The bash command string to run

@task.bash lets you build the command in Python, for example with f-strings or logic, and return it as a string. Airflow then runs that string like a BashOperator, with the same exit code rules and XCom of the last stdout line.

19. What a milestone is

In a project schedule, what is a milestone?

  1. A.A task that lasts more than one week
  2. B.A payment made to a vendor
  3. C.A significant point or event in the schedule, with zero duration
  4. D.A team celebration after a release
Show answer

Answer: C. A significant point or event in the schedule, with zero duration

A milestone marks an important moment, such as 'design approved' or 'go-live'. It has no duration and no work of its own. Milestones help stakeholders track progress at a high level.

20. Lead versus lag

What is the difference between a lead and a lag on a dependency?

  1. A.A lead lets the successor start earlier; a lag adds waiting time
  2. B.A lead adds waiting time; a lag lets the successor start earlier
  3. C.A lead is used only for milestones; a lag only for summary tasks
  4. D.They mean the same thing in different scheduling tools
Show answer

Answer: A. A lead lets the successor start earlier; a lag adds waiting time

A lag is a delay added between activities, such as waiting 3 days after pouring concrete before loading it. A lead is negative lag: the successor starts before the predecessor finishes, overlapping them.

Airflow intermediate interview questions medium

21. Limits of priority inheritance

A FreeRTOS mutex has priority inheritance. Which statement about its effect is true?

  1. A.It limits how long the high task waits but does not remove the wait
  2. B.It removes all blocking time for every high-priority task
  3. C.It also prevents deadlock between two different mutexes
  4. D.It makes mutexes safe to take and give from inside ISRs
Show answer

Answer: A. It limits how long the high task waits but does not remove the wait

Inheritance raises the holder priority so medium-priority tasks cannot stretch the wait. The high-priority task still waits until the holder finishes its critical section. It does nothing for deadlocks, and mutexes still cannot be used in ISRs.

22. Idle task and priority 0 tasks

A user task also runs at priority 0, the same as the idle task. What does configIDLE_SHOULD_YIELD = 1 change?

  1. A.The idle task is removed from the system entirely
  2. B.The user task at priority 0 can then never run
  3. C.The idle task yields each pass, so the user task gets more time
  4. D.The tick rate is doubled for priority 0 tasks
Show answer

Answer: C. The idle task yields each pass, so the user task gets more time

With this option, the idle task yields after each pass of its loop when other priority 0 tasks are ready, rather than using its full time slice. The user task then gets most of the CPU, though not perfectly evenly. Putting user tasks above idle avoids the question.

23. Utilisation limit under EDF

Independent periodic tasks with deadlines equal to periods are scheduled by earliest deadline first (EDF) on one core. Up to what total utilisation are they always schedulable?

  1. A.69% of the CPU
  2. B.83% of the CPU
  3. C.100% of the CPU
  4. D.50% of the CPU
Show answer

Answer: C. 100% of the CPU

EDF is optimal on one core for such tasks: if total utilisation is at most 1, all deadlines are met. Rate monotonic fixed priorities only guarantee this up to n(2^(1/n) − 1), about 69% for many tasks. Most RTOSes use fixed priorities because they are simpler and behave better under overload.

24. Safe retries in pipelines

An orchestrator retries a failed feature pipeline task, and the result table now has duplicate rows for that day. What design principle was missed?

  1. A.Tasks should never be retried
  2. B.Each task should run on a new cluster
  3. C.All tasks should write to the same table
  4. D.Tasks should be idempotent, for example overwriting the partition for that date instead of appending
Show answer

Answer: D. Tasks should be idempotent, for example overwriting the partition for that date instead of appending

An idempotent task gives the same result no matter how many times it runs. Writing by partition with overwrite or merge semantics makes retries and backfills safe. Appending blindly causes duplicates whenever a task is rerun.

25. Assets instead of tasks

Dagster encourages "software-defined assets". What is the main idea?

  1. A.You write tasks that never produce any stored output at all
  2. B.You declare data assets and their upstreams; runs build them
  3. C.You define only cron schedules and never any dependencies
  4. D.You store every data asset inside the scheduler database
Show answer

Answer: B. You declare data assets and their upstreams; runs build them

Instead of listing steps, you define the tables, files or models a pipeline produces and what each depends on. Dagster can then show freshness, lineage and which assets are stale, and rebuild only what is needed.

26. When a daily Airflow run starts

A daily DAG (midnight schedule) processes the data interval 2026-10-14 00:00 to 2026-10-15 00:00. When does the scheduler start this run?

  1. A.At 2026-10-15 00:00, after the interval has ended
  2. B.At 2026-10-14 00:00, at the start of the interval
  3. C.At 2026-10-14 12:00
  4. D.At a random time during 2026-10-14
Show answer

Answer: A. At 2026-10-15 00:00, after the interval has ended

Airflow runs a DAG at the end of its data interval, because only then is the whole day of data available. The run logical date is the start of the interval, 2026-10-14. Using data_interval_start and data_interval_end in queries keeps runs and backfills deterministic.

27. Join task skipped after a branch

A branch task picks either full_load or incremental_load, and both point to a notify task. notify always ends up skipped. What is the fix?

  1. A.Set retries=3 on the branch task itself
  2. B.Give notify trigger_rule="none_failed_min_one_success"
  3. C.Move notify so it is upstream of the branch
  4. D.Return both task ids from the branch callable
Show answer

Answer: B. Give notify trigger_rule="none_failed_min_one_success"

The branch not chosen is skipped, and with the default all_success rule a skipped upstream makes notify skipped too. none_failed_min_one_success runs notify when nothing failed and at least one upstream succeeded, which is exactly the join after a branch.

28. What depends_on_past does

A task has depends_on_past=True. Yesterday's run of this task failed. What happens to today's run of the same task?

  1. A.It runs normally and ignores yesterday
  2. B.It waits until yesterday's instance succeeds
  3. C.It is marked failed straight away
  4. D.It reruns yesterday's run first, then itself
Show answer

Answer: B. It waits until yesterday's instance succeeds

With depends_on_past=True, a task instance starts only if the same task in the previous DAG run succeeded or was skipped. Today's instance stays waiting until someone fixes and reruns yesterday's one. It suits loads that must be applied in order.

29. Setting parallelism by environment

In a Docker deployment you want to set [core] parallelism to 64 without editing airflow.cfg. Which environment variable does that?

  1. A.AIRFLOW_PARALLELISM=64
  2. B.AIRFLOW__CORE__PARALLELISM=64
  3. C.CORE_PARALLELISM=64
  4. D.AIRFLOW_CONN_PARALLELISM=64
Show answer

Answer: B. AIRFLOW__CORE__PARALLELISM=64

Airflow reads config from variables named AIRFLOW__{SECTION}__{KEY} with double underscores, and these override airflow.cfg. AIRFLOW_CONN_ (single underscore) is the prefix for defining connections, not settings.

30. Task instances in a 30-day rerun

A daily DAG has 5 tasks. You rerun it for all 30 days of April. How many task instances does that create?

  1. A.35
  2. B.30
  3. C.150
  4. D.5
Show answer

Answer: C. 150

Each DAG run gets one instance of every task: 30 runs × 5 tasks = 150 task instances. This is useful when sizing pools and worker capacity before a large rerun.

31. Task id inside a TaskGroup

A task with task_id="orders" sits inside a TaskGroup with group_id="extract". What is its full task id when referenced from another task?

  1. A.orders
  2. B.extract_orders
  3. C.orders.extract
  4. D.extract.orders
Show answer

Answer: D. extract.orders

By default a TaskGroup prefixes child task ids with the group id and a dot, giving extract.orders. You must use this full id in xcom_pull or branch return values. prefix_group_id=False turns the prefix off.

32. No emails during a backfill

A daily DAG ends with send_email. When you rerun 60 old days, you do not want 60 emails, but the current day should still send one. What helps?

  1. A.Put LatestOnlyOperator before send_email
  2. B.Set retries=0 on send_email
  3. C.Give send_email trigger_rule="all_done"
  4. D.Use a pool with 1 slot for send_email
Show answer

Answer: A. Put LatestOnlyOperator before send_email

LatestOnlyOperator skips its downstream tasks unless the run is the most recent scheduled one. Old runs during a backfill skip send_email; the latest run sends it. A 1-slot pool would still send all 60, just one at a time.

33. Only 16 tasks run at once

A DAG has 100 independent tasks and workers have 200 free slots, yet only 16 of its tasks run at a time. Which limit is most likely being hit?

  1. A.The default pool size
  2. B.max_active_runs
  3. C.The worker's CPU count
  4. D.max_active_tasks for the DAG
Show answer

Answer: D. max_active_tasks for the DAG

max_active_tasks caps how many task instances of one DAG can run at once across its active runs, and its default (max_active_tasks_per_dag) is 16. Raise it on the DAG if the downstream systems can cope. The default pool has 128 slots, so it is not the limit here.

34. A BashOperator that ends skipped

A BashOperator script checks for new files and runs exit 99 when there are none. What state does the task end in by default?

  1. A.Failed
  2. B.Up for retry
  3. C.Success
  4. D.Skipped
Show answer

Answer: D. Skipped

BashOperator treats exit code 99 as a skip by default (skip_on_exit_code=99). Exit 0 is success and any other non-zero code is a failure. This lets a script say "nothing to do" without a red task.

35. Running two branches at once

A @task.branch function decides that both refresh_cache and send_report should run, but not full_rebuild. What should it return?

  1. A."refresh_cache,send_report" as one string
  2. B.["refresh_cache", "send_report"]
  3. C.True
  4. D.None
Show answer

Answer: B. ["refresh_cache", "send_report"]

A branch callable can return one task id or a list of task ids; every listed direct downstream task runs and the others are skipped. Returning None skips all of them, and a comma-joined string is read as a single, unknown task id.

36. An optional file that may not come

A partner sometimes sends a bonus file; if it has not arrived in 2 hours, the DAG should carry on without error. What sensor setting fits?

  1. A.mode="poke" with retries=10
  2. B.timeout=None so it never stops
  3. C.poke_interval=1 to check faster
  4. D.timeout=7200 and soft_fail=True
Show answer

Answer: D. timeout=7200 and soft_fail=True

With soft_fail=True a sensor that times out is marked skipped instead of failed. Downstream tasks that need the file are skipped too, while tasks with a suitable trigger rule (like none_failed) carry on, and the run is not marked failed.

37. Catching broken DAGs before deploy

Broken DAG files keep reaching production. What simple test in CI catches most of them?

  1. A.Run airflow db reset in CI
  2. B.Check that every DAG has retries above 0
  3. C.Grep the files for the word "DAG"
  4. D.Load DagBag and assert import_errors is empty
Show answer

Answer: D. Load DagBag and assert import_errors is empty

Loading the DAG folder with DagBag(include_examples=False) imports every file like the DAG processor does. import_errors lists syntax errors, missing imports and cycles. Teams often add checks for tags, owners or retries on top.

38. What a BashOperator pushes

A BashOperator script prints three lines: "starting", "rows=500" and "/data/out_20260402.csv". What does it push to XCom by default?

  1. A.All three lines as a list
  2. B."/data/out_20260402.csv"
  3. C.Nothing; BashOperator never pushes XCom
  4. D.The exit code 0
Show answer

Answer: B. "/data/out_20260402.csv"

With do_xcom_push=True (the default), BashOperator pushes the last line written to stdout as return_value. Printing the output path last is a common way to hand it to the next task.

39. Mapping over matched pairs

You have three (source, target) pairs and want exactly three mapped copies, not nine. Which call does that?

  1. A.copy.expand(source=sources, target=targets)
  2. B.copy.partial(source=sources).expand(target=targets)
  3. C.copy.expand_kwargs([{"source": s, "target": t} for s, t in pairs])
  4. D.copy.expand(pairs=pairs * 3)
Show answer

Answer: C. copy.expand_kwargs([{"source": s, "target": t} for s, t in pairs])

expand() with two lists makes the cross product, 3 × 3 = 9 copies. expand_kwargs takes a list of dicts and creates one mapped instance per dict, so each source stays with its own target.

40. Forward pass duration

Activity A takes 3 days and starts the project. B (5 days) and C (2 days) both follow A. D (4 days) follows both B and C. How long is the project?

  1. A.14 days
  2. B.9 days
  3. C.12 days
  4. D.10 days
Show answer

Answer: C. 12 days

A finishes on day 3. B finishes on day 8 and C on day 5, so D can only start after the later one, on day 8. D finishes on day 12, and the critical path is A-B-D (3 + 5 + 4).

Airflow interview questions for experienced candidates hard

41. Worst-case response time of the lowest task

Fixed-priority preemptive tasks (C, T) in priority order: T1 = (1, 4), T2 = (2, 6), T3 = (3, 12), deadlines equal to periods. Using response time analysis R = C3 + Σ ceil(R/Ti) × Ci, what is the worst-case response time of T3?

  1. A.10
  2. B.6
  3. C.12
  4. D.7
Show answer

Answer: A. 10

Start with R = 3 + 1 + 2 = 6. Then R = 3 + ceil(6/4)×1 + ceil(6/6)×2 = 7, then 3 + 2 + 4 = 9, then 3 + 3 + 4 = 10, and 3 + ceil(10/4) + 2×ceil(10/6) = 10 again, so it converges at 10. Since 10 ≤ 12, T3 meets its deadline.

42. Above the RM bound but still schedulable

A task set has utilisation 0.83, above the 3-task rate monotonic bound of about 0.78. What can you conclude?

  1. A.The task set is sure to miss deadlines under rate monotonic
  2. B.The task set is schedulable, because 0.83 is below 1.0
  3. C.Nothing yet; the bound is only sufficient, so run an exact test
  4. D.The design must move to round-robin scheduling instead
Show answer

Answer: C. Nothing yet; the bound is only sufficient, so run an exact test

The Liu and Layland bound is sufficient but not necessary: sets under it always pass, sets above it may still pass. Response time analysis gives an exact answer for fixed priorities. Harmonic periods, for example, can be schedulable up to 100%.

43. Network throughput collapses

With FreeRTOS+TCP, the IP task is priority 2, the Ethernet driver task priority 4, and the app task that reads sockets priority 3. Throughput is poor. What ordering is usually recommended?

  1. A.Driver task highest, then the IP task, then app tasks
  2. B.App task highest, then the driver, then the IP task
  3. C.All three tasks at the same priority, time sliced
  4. D.The IP task at the idle priority, the rest above it
Show answer

Answer: A. Driver task highest, then the IP task, then app tasks

The driver must move frames in and out quickly, and the IP task must process them before app tasks consume data. If an app task outranks the IP task, it can starve the stack it is waiting on. FreeRTOS+TCP docs recommend this order.

44. Jitter of tick-driven periodic tasks

Periodic tasks are released by the 1 kHz tick, and a higher-priority task sometimes runs 300 µs at the same tick. What is the start jitter of a lower task released on that tick?

  1. A.Exactly 0 µs, because the tick is exact
  2. B.Up to 1 ms every time
  3. C.About 300 ms
  4. D.Up to about 300 µs, plus any ISR and switch time
Show answer

Answer: D. Up to about 300 µs, plus any ISR and switch time

All tasks released on a tick become ready together, and the highest runs first. The lower task can start up to the higher task run time later, about 300 µs, plus kernel and ISR overhead. If that matters, trigger the critical task from its own hardware timer.

45. Deadline shorter than period

Task A has period 100 ms but deadline 5 ms after release. Task B has period 20 ms and deadline 20 ms. Which priority order fits deadline monotonic scheduling?

  1. A.B above A, because B has the shorter period
  2. B.A above B, because A has the shorter deadline
  3. C.Equal priorities with time slicing
  4. D.Whichever has the longer run time first
Show answer

Answer: B. A above B, because A has the shorter deadline

When deadlines are shorter than periods, deadline monotonic ordering, by relative deadline, is optimal among fixed priorities. A must finish within 5 ms, so it ranks above B even though it runs less often. Rate monotonic would rank them the wrong way.

46. Cooperative Zephyr thread hogs the CPU

A Zephyr thread at priority -2 runs a 50 ms checksum loop. Higher-numbered preemptible threads, including the BLE host thread, miss timing. What helps most?

  1. A.Make it preemptible, or k_yield inside the loop
  2. B.Give the BLE host thread a priority of 20
  3. C.Turn on CONFIG_TIMESLICING for all threads
  4. D.Raise the system tick rate to 10 kHz
Show answer

Answer: A. Make it preemptible, or k_yield inside the loop

A cooperative thread is never preempted by other threads, so a long loop holds the CPU for its full length. Time slicing does not apply to it. Make it preemptible with a low priority, or break the loop up with yields if it must stay cooperative.

47. Critical Pod cannot schedule on a full cluster

The cluster is full. A new payments Pod with a high PriorityClass is created and other Pods without a priority class are running. What will the scheduler try?

  1. A.Wait until the autoscaler adds a node, never evicting
  2. B.Evict lower-priority Pods on a node so payments can fit
  3. C.Place payments over the node capacity for a short time
  4. D.Reject payments because the ResourceQuota is full
Show answer

Answer: B. Evict lower-priority Pods on a node so payments can fit

If a pending Pod cannot fit, the scheduler looks for a node where removing lower-priority Pods would make room, and preempts them gracefully. Pods without a PriorityClass get the default priority, usually 0. Use this carefully, and protect important lower-priority work with PDBs.

48. Filtering by now() in a task

A daily Airflow task loads "yesterday’s" rows using datetime.now() − 1 day. Why is this a problem for reruns and backfills?

  1. A.datetime.now() is not allowed inside Airflow tasks
  2. B.It makes the task run twice each day
  3. C.Reruns load the wrong day; use the run’s data interval
  4. D.Airflow converts now() to the DAG start date
Show answer

Answer: C. Reruns load the wrong day; use the run’s data interval

A rerun of last Monday’s run would load the day before today, not the day before Monday. Using the run’s data_interval_start and data_interval_end (or logical date) ties each run to a fixed period, so reruns and backfills are deterministic.

49. Cron with both day fields set

A DAG uses schedule "0 9 1 * 1", meant as "9 AM on the 1st if it is a Monday". When does it actually run?

  1. A.Only when the 1st of a month is a Monday
  2. B.On the 1st of every month and on every Monday
  3. C.Only on Mondays
  4. D.Only on the 1st of each month
Show answer

Answer: B. On the 1st of every month and on every Monday

In standard cron, when both day-of-month and day-of-week are restricted, a day matches if either one matches. So this runs on every Monday and also on every 1st. For "1st and Monday" you need a custom timetable or a check inside the DAG.

50. Tasks waiting while workers sit idle

Celery workers are mostly idle, yet several tasks of DAG finance_close stay in the scheduled state for an hour. They all use pool="warehouse", which has 3 slots. What should you check first?

  1. A.Whether the broker has run out of disk
  2. B.Whether other tasks hold all 3 warehouse slots
  3. C.Whether the DAG file has a syntax error
  4. D.Whether the tasks have retries set to 0
Show answer

Answer: B. Whether other tasks hold all 3 warehouse slots

A task leaves the scheduled state only when the scheduler can give it a pool slot and other limits allow it. If long tasks from other DAGs hold all 3 warehouse slots, these tasks wait however idle the workers are. Check the Pools page for running and queued slots, and consider priority_weight for urgent work.

51. Doubled rows after a retry

A task runs INSERT INTO sales SELECT ... for the day, then fails while refreshing a summary. The retry succeeds, and that day's sales now appear twice. What is the right fix?

INSERT INTO sales SELECT * FROM staging WHERE dt = '{{ ds }}';
REFRESH MATERIALIZED VIEW sales_summary;  -- failed here
  1. A.Set retries=0 so the task never runs twice
  2. B.Delete the day's rows, then insert, in one transaction
  3. C.Use a pool with only one slot for the task
  4. D.Run the summary refresh before the insert step
Show answer

Answer: B. Delete the day's rows, then insert, in one transaction

Airflow reruns the whole task on retry, so every task must be safe to run twice. Deleting the rows for dt = ds and inserting them again (or MERGE / partition overwrite) makes the step idempotent. Removing retries only hides the problem until someone clears the task.

52. Effective priority of a root task

All tasks have priority_weight=1 and the default weight_rule="downstream". What is the effective priority of a?

a >> [b, c]
b >> d
  1. A.1
  2. B.2
  3. C.3
  4. D.4
Show answer

Answer: D. 4

With the downstream rule, a task's effective weight is its own weight plus the weights of all its downstream tasks. a has b, c and d below it, so 1 + 1 + 1 + 1 = 4. This makes the scheduler favour tasks that unblock the most work.

53. Mapping over 2,000 items

list_ids returns 2,000 ids and score.expand(id=list_ids()) follows. With default settings, what happens?

  1. A.The run fails because 2,000 exceeds max_map_length (1024)
  2. B.2,000 mapped instances run normally
  3. C.Only the first 1024 ids are processed
  4. D.The instances are created in batches of 1024 silently
Show answer

Answer: A. The run fails because 2,000 exceeds max_map_length (1024)

[core] max_map_length defaults to 1024, and a mapping input longer than that raises an error instead of being cut. Raise the setting if you really need it, or better, map over batches of ids so you have fewer, larger task instances.

54. Consumer DAG ran with no new data

A producer task declares outlets=[Asset("s3://dw/orders")]. Today it found no new orders, wrote nothing, and succeeded. The consumer DAG still ran. Why?

  1. A.Asset events fire on a fixed timer every day
  2. B.The consumer runs whenever any producer task fails
  3. C.An event is logged on task success, not on data change
  4. D.The consumer reads S3 modification times itself
Show answer

Answer: C. An event is logged on task success, not on data change

Airflow does not inspect the data. When a task with an outlet succeeds, Airflow records an asset event, and consumer DAGs scheduled on that asset are triggered. If no new data should mean no event, skip the task or emit events only when something was written.

55. Run when either feed updates

A DAG should run whenever either the UAE feed or the India feed asset is updated, not wait for both. How is the schedule written?

  1. A.schedule=[uae_feed, india_feed]
  2. B.schedule=(uae_feed | india_feed)
  3. C.schedule=(uae_feed & india_feed)
  4. D.schedule="uae_feed or india_feed"
Show answer

Answer: B. schedule=(uae_feed | india_feed)

A plain list of assets means all must update. Asset expressions use | for "any of" and & for "all of", so (uae_feed | india_feed) triggers on either. A string is read as a cron or preset, not as assets.

56. Summing results of mapped tasks

count_rows is mapped over 12 files and returns an int each. A normal downstream task total(counts) receives count_rows's output. What is counts?

counts = count_rows.expand(path=files)
total(counts)
  1. A.Only the value from the last mapped instance
  2. B.A sequence of the 12 returned ints
  3. C.The sum of the 12 ints, added by Airflow
  4. D.None, because mapped tasks cannot return values
Show answer

Answer: B. A sequence of the 12 returned ints

A non-mapped task that consumes a mapped task's output gets a lazy sequence of all the mapped return values, in map index order. total can then call sum(counts). This is the standard map-reduce pattern in Airflow.

57. Large XComs without filling the database

Teams keep returning medium-sized results (5–50 MB) from tasks and the metadata database is suffering. Which setup keeps the TaskFlow style but moves large values out of the database?

  1. A.Raise the database disk size each month
  2. B.Ban all return values in code review
  3. C.Store results in Airflow Variables instead
  4. D.An object storage XCom backend with a size threshold
Show answer

Answer: D. An object storage XCom backend with a size threshold

A custom XCom backend, such as the object storage backend in the common.io provider, writes values above a threshold to S3 or GCS and keeps only a reference in the database. Small values stay in the database, and task code does not change.

58. Two runs overwriting one temp file

With max_active_runs=4 during a backfill, a task writes /tmp/extract.csv on a shared volume and the next task loads it. Some days load another day's data. What is the fix?

  1. A.Set retries=3 on the load task
  2. B.Use a pool with 4 slots
  3. C.Raise execution_timeout on both tasks
  4. D.Include the run id or ds in the file path
Show answer

Answer: D. Include the run id or ds in the file path

Parallel runs share the same fixed path, so one run overwrites the file another run is about to load. Making paths unique per run, for example /tmp/extract_{{ ds_nodash }}.csv or a run_id folder, keeps runs isolated and safe to rerun.

59. ds moved by a day after a timetable change

A daily midnight DAG moves from CronDataIntervalTimetable to CronTriggerTimetable. For the run that starts at 00:00 on 11 March 2026, what is {{ ds }} now?

  1. A.2026-03-11
  2. B.2026-03-10, same as before
  3. C.2026-03-12
  4. D.Empty, because ds is not set
Show answer

Answer: A. 2026-03-11

CronDataIntervalTimetable runs at the end of the interval, so the midnight run on 11 March has logical date 10 March. CronTriggerTimetable has no interval and its logical date is the trigger time itself, 11 March. Queries filtered on ds shift by a day unless you adjust them.

60. Finishing old runs before new ones

During a 30-day backfill, Airflow starts the first task of many runs before finishing any run, so complete days appear slowly. Which weight_rule makes later tasks of started runs go first?

  1. A.weight_rule="downstream"
  2. B.weight_rule="absolute" with weight 0
  3. C.weight_rule="upstream"
  4. D.weight_rule="random"
Show answer

Answer: C. weight_rule="upstream"

With the default downstream rule, early tasks get the highest weight, so the scheduler prefers starting new runs. With upstream, a task's weight includes all tasks above it, so tasks deep in a DAG win and in-flight runs finish sooner. There is no random rule.

Ready to test yourself?

Take a 15-question Airflow MCQ test with a score at the end, or practise the full Airflow question bank and earn points on the leaderboard.