This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 55d648ec094 use of debugpy to run airflow components via breeze 
(#51763)
55d648ec094 is described below

commit 55d648ec094fc6f22a28f34bef0656a062705494
Author: Kalyan R <[email protected]>
AuthorDate: Thu Jul 24 17:05:57 2025 +0530

    use of debugpy to run airflow components via breeze (#51763)
    
    * debug support in breeze
    
    * fix celery env var
    
    * Add debug options for Airflow components and update related constants
    
    * Add debug options for Airflow components and update related constants
    
    * refactor
    
    * update documentation and add setup_vscode
    
    * Remove section on overriding default debug ports in VSCode setup 
documentation
    
    * fix base-ports
    
    * fix base-ports
    
    * update docs
    
    * add webserver details in docs
    
    * update docs
    
    * update docs
    
    * update docs
---
 contributing-docs/06_development_environments.rst  |   3 +
 .../20_debugging_airflow_components.rst            | 162 +++++++++++++++++++++
 contributing-docs/README.rst                       |   3 +
 dev/breeze/doc/03_developer_tasks.rst              |   6 +
 dev/breeze/doc/images/output_start-airflow.svg     |  40 ++++-
 dev/breeze/doc/images/output_start-airflow.txt     |   2 +-
 .../src/airflow_breeze/commands/common_options.py  |  19 +++
 .../airflow_breeze/commands/developer_commands.py  |   8 +
 .../commands/developer_commands_config.py          |   4 +
 dev/breeze/src/airflow_breeze/global_constants.py  |   7 +
 .../src/airflow_breeze/params/shell_params.py      |  42 ++++++
 scripts/ci/docker-compose/base-ports.yml           |   7 +
 scripts/in_container/bin/run_tmux                  |  48 +++++-
 setup_vscode.py                                    | 129 ++++++++++++++++
 14 files changed, 468 insertions(+), 12 deletions(-)

diff --git a/contributing-docs/06_development_environments.rst 
b/contributing-docs/06_development_environments.rst
index 285f87d99eb..5ce138a3f1c 100644
--- a/contributing-docs/06_development_environments.rst
+++ b/contributing-docs/06_development_environments.rst
@@ -158,3 +158,6 @@ Typically, you are recommended to use multiple of these 
environments depending o
 
 If you want to learn more details about setting up your local virtualenv, 
follow to the
 `Local virtualenv <07_local_virtualenv.rst>`__ document.
+
+For detailed information about debugging Airflow components using Breeze, see 
the
+`Debugging Airflow Components <20_debugging_airflow_components.rst>`__ guide.
diff --git a/contributing-docs/20_debugging_airflow_components.rst 
b/contributing-docs/20_debugging_airflow_components.rst
new file mode 100644
index 00000000000..c6502f787fb
--- /dev/null
+++ b/contributing-docs/20_debugging_airflow_components.rst
@@ -0,0 +1,162 @@
+ .. Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+ ..   http://www.apache.org/licenses/LICENSE-2.0
+
+ .. Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+Debugging Airflow Components with Breeze
+========================================
+
+Breeze provides debugging support for Airflow components using the ``--debug`` 
and ``--debugger`` flags
+in the ``breeze start-airflow`` command.
+
+Starting Airflow with Debug Support
+----------------------------------
+
+To start Airflow with debugging enabled, use the ``--debug`` flag to specify 
which components you want to debug:
+
+.. code-block:: bash
+
+    # Debug the scheduler
+    breeze start-airflow --debug scheduler
+
+    # Debug multiple components
+    breeze start-airflow --debug scheduler --debug triggerer
+
+    # Debug all components
+    breeze start-airflow --debug scheduler --debug triggerer --debug 
api-server --debug dag-processor
+
+    # Debug with CeleryExecutor
+    breeze start-airflow -b postgres -P 17 --executor CeleryExecutor  --debug 
scheduler --debug dag-processor --debug api-server --debug triggerer --debug 
celery-worker
+
+    # Debug Webserver for Airflow 2.x
+    breeze start-airflow --debug webserver
+
+Available Components for Debugging
+----------------------------------
+
+* **scheduler** - The Airflow scheduler that monitors DAGs and triggers task 
instances
+* **triggerer** - The triggerer service that handles deferred tasks and 
triggers
+* **api-server** - The Airflow REST API server
+* **dag-processor** - The DAG processor service (when using standalone DAG 
processor)
+* **edge-worker** - The edge worker service (when using EdgeExecutor)
+* **celery-worker** - Celery worker processes (when using CeleryExecutor)
+
+Debugger Options
+----------------
+
+Breeze supports two debugger options:
+
+* **debugpy** (default)
+* **pydevd-pycharm**
+
+.. code-block:: bash
+
+    # Use debugpy (default)
+    breeze start-airflow --debug scheduler --debugger debugpy
+
+    # Use PyCharm debugger
+    breeze start-airflow --debug scheduler --debugger pydevd-pycharm
+
+Setting up VSCode for Remote Debugging
+--------------------------------------
+
+1. **Install Required Extensions**
+
+   Install the following VSCode extensions:
+   * Python (ms-python.python)
+   * Python Debugger (ms-python.debugpy)
+
+2. **Create Launch Configuration**
+
+   Create or update your ``.vscode/launch.json`` file. The easiest way is to 
run the setup script:
+
+   .. code-block:: bash
+
+       python setup_vscode.py
+
+   This will create debug configurations for all Airflow components. Here's an 
example configuration for the scheduler:
+
+   .. code-block:: json
+
+       {
+           "name": "Debug Airflow Scheduler",
+           "type": "debugpy",
+           "request": "attach",
+           "justMyCode": false,
+           "connect": {
+               "host": "localhost",
+               "port": 50231
+           },
+           "pathMappings": [
+               {
+                   "localRoot": "${workspaceFolder}",
+                   "remoteRoot": "/opt/airflow"
+               }
+           ]
+       }
+
+3. **Port Mapping**
+
+   Each component uses a different debug port. These ports are automatically 
assigned by Breeze
+   when you start Airflow with debugging enabled:
+
+   * **Scheduler**: 50231
+   * **DAG Processor**: 50232
+   * **Triggerer**: 50233
+   * **API Server**: 50234
+   * **Celery Worker**: 50235
+   * **Edge Worker**: 50236
+   * **Web Server**: 50237
+
+   These ports are exposed from the Breeze container to your host machine, 
allowing your IDE
+   to connect to the debugger running inside the container.
+
+
+Debugging Workflow
+------------------
+
+1. **Start Airflow with Debug Support**
+
+   .. code-block:: bash
+
+       breeze start-airflow --debug scheduler --debugger debugpy
+
+2. **Set Breakpoints**
+
+   In VSCode, set breakpoints in your Airflow code by clicking in the gutter 
next to line numbers.
+
+3. **Attach Debugger**
+
+   - Open the Debug panel in VSCode (Ctrl+Shift+D / Cmd+Shift+D)
+   - Select the appropriate debug configuration (e.g., "Debug Airflow 
Scheduler")
+   - Click the green play button or press F5
+
+4. **Trigger Debugging**
+
+   Perform an action that will trigger the code path with your breakpoint:
+
+   - For scheduler: Trigger a DAG or wait for scheduled execution
+   - For API server: Make an API call
+   - For triggerer: Create a deferred task
+   - For DAG processor: Parse a DAG file
+
+5. **Debug Session**
+
+   Once the breakpoint is hit:
+
+   - Inspect variables in the Variables panel
+   - Use the Debug Console to evaluate expressions
+   - Step through code using F10 (step over), F11 (step into), F12 (step out)
+   - Continue execution with F5
diff --git a/contributing-docs/README.rst b/contributing-docs/README.rst
index ebe192b0e05..c58a3089b42 100644
--- a/contributing-docs/README.rst
+++ b/contributing-docs/README.rst
@@ -121,3 +121,6 @@ You can also dive deeper into more specific areas that are 
important for contrib
 
 * `Execution API versioning <19_execution_api_versioning.rst>`__ describes how 
to
   version the Task Execution API and how to add new versions of the API.
+
+* `Debugging Airflow Components <20_debugging_airflow_components.rst>`__ 
describes how to debug
+  Airflow components using Breeze with debugpy and VSCode integration.
diff --git a/dev/breeze/doc/03_developer_tasks.rst 
b/dev/breeze/doc/03_developer_tasks.rst
index d269e98a0c8..fd8530684b4 100644
--- a/dev/breeze/doc/03_developer_tasks.rst
+++ b/dev/breeze/doc/03_developer_tasks.rst
@@ -193,6 +193,12 @@ your local sources to the ``/opt/airflow`` location of the 
sources within the co
     :align: center
     :alt: Source code mapping
 
+.. note::
+
+   For comprehensive debugging documentation using the new ``--debug`` and 
``--debugger`` flags
+   with VSCode and debugpy, see the `Debugging Airflow Components 
<../../contributing-docs/20_debugging_airflow_components.rst>`__
+   guide.
+
 Building the documentation
 --------------------------
 
diff --git a/dev/breeze/doc/images/output_start-airflow.svg 
b/dev/breeze/doc/images/output_start-airflow.svg
index 2d59895ce72..bf172e819a5 100644
--- a/dev/breeze/doc/images/output_start-airflow.svg
+++ b/dev/breeze/doc/images/output_start-airflow.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 3514.7999999999997" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 3661.2" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-start-airflow-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="3463.7999999999997" />
+      <rect x="0" y="0" width="1463.0" height="3610.2" />
     </clipPath>
     <clipPath id="breeze-start-airflow-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -468,9 +468,27 @@
 <clipPath id="breeze-start-airflow-line-140">
     <rect x="0" y="3417.5" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-start-airflow-line-141">
+    <rect x="0" y="3441.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-start-airflow-line-142">
+    <rect x="0" y="3466.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-start-airflow-line-143">
+    <rect x="0" y="3490.7" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-start-airflow-line-144">
+    <rect x="0" y="3515.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-start-airflow-line-145">
+    <rect x="0" y="3539.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-start-airflow-line-146">
+    <rect x="0" y="3563.9" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="3512.8" rx="8"/><text 
class="breeze-start-airflow-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;start-airflow</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="3659.2" rx="8"/><text 
class="breeze-start-airflow-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;start-airflow</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -616,12 +634,18 @@
 </text><text class="breeze-start-airflow-r5" x="0" y="3265.2" 
textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-133)">╭─</text><text 
class="breeze-start-airflow-r5" x="24.4" y="3265.2" textLength="183" 
clip-path="url(#breeze-start-airflow-line-133)">&#160;Other&#160;options&#160;</text><text
 class="breeze-start-airflow-r5" x="207.4" y="3265.2" textLength="1232.2" 
clip-path="url(#breeze-start-airflow-line-133)">────────────────────────────────────────────────────────────────────
 [...]
 </text><text class="breeze-start-airflow-r5" x="0" y="3289.6" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-134)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3289.6" textLength="256.2" 
clip-path="url(#breeze-start-airflow-line-134)">--forward-credentials</text><text
 class="breeze-start-airflow-r6" x="305" y="3289.6" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-134)">-f</text><text 
class="breeze-start-airflow-r1" x="353.8" y="3289.6" textLength=" [...]
 </text><text class="breeze-start-airflow-r5" x="0" y="3314" textLength="1464" 
clip-path="url(#breeze-start-airflow-line-135)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-start-airflow-r1" x="1464" y="3314" textLength="12.2" 
clip-path="url(#breeze-start-airflow-line-135)">
-</text><text class="breeze-start-airflow-r5" x="0" y="3338.4" 
textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-136)">╭─</text><text 
class="breeze-start-airflow-r5" x="24.4" y="3338.4" textLength="195.2" 
clip-path="url(#breeze-start-airflow-line-136)">&#160;Common&#160;options&#160;</text><text
 class="breeze-start-airflow-r5" x="219.6" y="3338.4" textLength="1220" 
clip-path="url(#breeze-start-airflow-line-136)">───────────────────────────────────────────────────────────────────
 [...]
-</text><text class="breeze-start-airflow-r5" x="0" y="3362.8" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-137)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3362.8" textLength="97.6" 
clip-path="url(#breeze-start-airflow-line-137)">--answer</text><text 
class="breeze-start-airflow-r6" x="158.6" y="3362.8" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-137)">-a</text><text 
class="breeze-start-airflow-r1" x="207.4" y="3362.8" textLength="317.2" clip- 
[...]
-</text><text class="breeze-start-airflow-r5" x="0" y="3387.2" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-138)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3387.2" textLength="109.8" 
clip-path="url(#breeze-start-airflow-line-138)">--dry-run</text><text 
class="breeze-start-airflow-r6" x="158.6" y="3387.2" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-138)">-D</text><text 
class="breeze-start-airflow-r1" x="207.4" y="3387.2" textLength="719.8" cli 
[...]
-</text><text class="breeze-start-airflow-r5" x="0" y="3411.6" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-139)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3411.6" textLength="109.8" 
clip-path="url(#breeze-start-airflow-line-139)">--verbose</text><text 
class="breeze-start-airflow-r6" x="158.6" y="3411.6" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-139)">-v</text><text 
class="breeze-start-airflow-r1" x="207.4" y="3411.6" textLength="585.6" cli 
[...]
-</text><text class="breeze-start-airflow-r5" x="0" y="3436" textLength="12.2" 
clip-path="url(#breeze-start-airflow-line-140)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3436" textLength="73.2" 
clip-path="url(#breeze-start-airflow-line-140)">--help</text><text 
class="breeze-start-airflow-r6" x="158.6" y="3436" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-140)">-h</text><text 
class="breeze-start-airflow-r1" x="207.4" y="3436" textLength="329.4" 
clip-path="url( [...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3338.4" 
textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-136)">╭─</text><text 
class="breeze-start-airflow-r5" x="24.4" y="3338.4" textLength="231.8" 
clip-path="url(#breeze-start-airflow-line-136)">&#160;Debugging&#160;options&#160;</text><text
 class="breeze-start-airflow-r5" x="256.2" y="3338.4" textLength="1183.4" 
clip-path="url(#breeze-start-airflow-line-136)">──────────────────────────────────────────────────────────────
 [...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3362.8" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-137)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3362.8" textLength="85.4" 
clip-path="url(#breeze-start-airflow-line-137)">--debug</text><text 
class="breeze-start-airflow-r1" x="195.2" y="3362.8" textLength="1244.4" 
clip-path="url(#breeze-start-airflow-line-137)">Enable&#160;debugging&#160;for&#160;specific&#160;Airflow&#160;components.&#160;Can&#160;be
 [...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3387.2" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-138)">│</text><text 
class="breeze-start-airflow-r1" x="195.2" y="3387.2" textLength="1244.4" 
clip-path="url(#breeze-start-airflow-line-138)">api-server,&#160;dag-processor,&#160;edge-worker,&#160;celery-worker.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3411.6" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-139)">│</text><text 
class="breeze-start-airflow-r7" x="195.2" y="3411.6" textLength="1244.4" 
clip-path="url(#breeze-start-airflow-line-139)">(scheduler&#160;|&#160;triggerer&#160;|&#160;api-server&#160;|&#160;dag-processor&#160;|&#160;edge-worker&#160;|&#160;celery-worker)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3436" textLength="12.2" 
clip-path="url(#breeze-start-airflow-line-140)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3436" textLength="122" 
clip-path="url(#breeze-start-airflow-line-140)">--debugger</text><text 
class="breeze-start-airflow-r1" x="195.2" y="3436" textLength="597.8" 
clip-path="url(#breeze-start-airflow-line-140)">Debugger&#160;to&#160;use&#160;for&#160;debugging&#160;Airflow&#160;components.</text><text
 clas [...]
 </text><text class="breeze-start-airflow-r5" x="0" y="3460.4" 
textLength="1464" 
clip-path="url(#breeze-start-airflow-line-141)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-start-airflow-r1" x="1464" y="3460.4" textLength="12.2" 
clip-path="url(#breeze-start-airflow-line-141)">
+</text><text class="breeze-start-airflow-r5" x="0" y="3484.8" 
textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-142)">╭─</text><text 
class="breeze-start-airflow-r5" x="24.4" y="3484.8" textLength="195.2" 
clip-path="url(#breeze-start-airflow-line-142)">&#160;Common&#160;options&#160;</text><text
 class="breeze-start-airflow-r5" x="219.6" y="3484.8" textLength="1220" 
clip-path="url(#breeze-start-airflow-line-142)">───────────────────────────────────────────────────────────────────
 [...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3509.2" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-143)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3509.2" textLength="97.6" 
clip-path="url(#breeze-start-airflow-line-143)">--answer</text><text 
class="breeze-start-airflow-r6" x="158.6" y="3509.2" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-143)">-a</text><text 
class="breeze-start-airflow-r1" x="207.4" y="3509.2" textLength="317.2" clip- 
[...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3533.6" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-144)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3533.6" textLength="109.8" 
clip-path="url(#breeze-start-airflow-line-144)">--dry-run</text><text 
class="breeze-start-airflow-r6" x="158.6" y="3533.6" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-144)">-D</text><text 
class="breeze-start-airflow-r1" x="207.4" y="3533.6" textLength="719.8" cli 
[...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3558" textLength="12.2" 
clip-path="url(#breeze-start-airflow-line-145)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3558" textLength="109.8" 
clip-path="url(#breeze-start-airflow-line-145)">--verbose</text><text 
class="breeze-start-airflow-r6" x="158.6" y="3558" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-145)">-v</text><text 
class="breeze-start-airflow-r1" x="207.4" y="3558" textLength="585.6" 
clip-path=" [...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3582.4" 
textLength="12.2" clip-path="url(#breeze-start-airflow-line-146)">│</text><text 
class="breeze-start-airflow-r4" x="24.4" y="3582.4" textLength="73.2" 
clip-path="url(#breeze-start-airflow-line-146)">--help</text><text 
class="breeze-start-airflow-r6" x="158.6" y="3582.4" textLength="24.4" 
clip-path="url(#breeze-start-airflow-line-146)">-h</text><text 
class="breeze-start-airflow-r1" x="207.4" y="3582.4" textLength="329.4" clip-pa 
[...]
+</text><text class="breeze-start-airflow-r5" x="0" y="3606.8" 
textLength="1464" 
clip-path="url(#breeze-start-airflow-line-147)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-start-airflow-r1" x="1464" y="3606.8" textLength="12.2" 
clip-path="url(#breeze-start-airflow-line-147)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_start-airflow.txt 
b/dev/breeze/doc/images/output_start-airflow.txt
index ad332f31642..063b275e3ba 100644
--- a/dev/breeze/doc/images/output_start-airflow.txt
+++ b/dev/breeze/doc/images/output_start-airflow.txt
@@ -1 +1 @@
-6a6bd606f4cbcec80a6335b1c16fcddc
+95c9bb3df25c755c805283de1424b9bb
diff --git a/dev/breeze/src/airflow_breeze/commands/common_options.py 
b/dev/breeze/src/airflow_breeze/commands/common_options.py
index 15a5cbbce2e..e323801320a 100644
--- a/dev/breeze/src/airflow_breeze/commands/common_options.py
+++ b/dev/breeze/src/airflow_breeze/commands/common_options.py
@@ -477,6 +477,25 @@ option_install_airflow_with_constraints_default_true = 
click.option(
     envvar="INSTALL_AIRFLOW_WITH_CONSTRAINTS",
     help="Install airflow in a separate step, with constraints determined from 
package or airflow version.",
 )
+option_debug_components = click.option(
+    "--debug",
+    "debug_components",
+    help="Enable debugging for specific Airflow components. Can be one or more 
of: "
+    "scheduler, triggerer, api-server, dag-processor, edge-worker, 
celery-worker.",
+    type=BetterChoice(
+        ["scheduler", "triggerer", "api-server", "dag-processor", 
"edge-worker", "celery-worker"]
+    ),
+    multiple=True,
+    envvar="DEBUG_COMPONENTS",
+)
+option_debugger = click.option(
+    "--debugger",
+    help="Debugger to use for debugging Airflow components.",
+    type=BetterChoice(["debugpy", "pydevd-pycharm"]),
+    default="debugpy",
+    show_default=True,
+    envvar="DEBUGGER",
+)
 
 
 def _is_number_greater_than_expected(value: str) -> bool:
diff --git a/dev/breeze/src/airflow_breeze/commands/developer_commands.py 
b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
index b3b2b96af71..3b59bded514 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
@@ -41,6 +41,8 @@ from airflow_breeze.commands.common_options import (
     option_builder,
     option_clean_airflow_installation,
     option_db_reset,
+    option_debug_components,
+    option_debugger,
     option_docker_host,
     option_downgrade_pendulum,
     option_downgrade_sqlalchemy,
@@ -504,6 +506,8 @@ option_auth_manager_start_airflow = click.option(
 @option_celery_broker
 @option_celery_flower
 @option_db_reset
+@option_debug_components
+@option_debugger
 @option_docker_host
 @option_dry_run
 @option_executor_start_airflow
@@ -548,6 +552,8 @@ def start_airflow(
     celery_flower: bool,
     clean_airflow_installation: bool,
     db_reset: bool,
+    debug_components: tuple[str, ...],
+    debugger: str,
     dev_mode: bool,
     docker_host: str | None,
     executor: str | None,
@@ -617,6 +623,8 @@ def start_airflow(
         celery_broker=celery_broker,
         celery_flower=celery_flower,
         clean_airflow_installation=clean_airflow_installation,
+        debug_components=debug_components,
+        debugger=debugger,
         db_reset=db_reset,
         dev_mode=dev_mode,
         docker_host=docker_host,
diff --git 
a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py 
b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
index dfb01ff83ed..b4332f7c1a6 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
@@ -293,6 +293,10 @@ DEVELOPER_PARAMETERS: dict[str, list[dict[str, str | 
list[str]]]] = {
                 "--forward-credentials",
             ],
         },
+        {
+            "name": "Debugging options",
+            "options": ["--debug", "--debugger"],
+        },
     ],
     "breeze exec": [
         {"name": "Drops in the interactive shell of active airflow container"},
diff --git a/dev/breeze/src/airflow_breeze/global_constants.py 
b/dev/breeze/src/airflow_breeze/global_constants.py
index c640cf34210..25e13a26c39 100644
--- a/dev/breeze/src/airflow_breeze/global_constants.py
+++ b/dev/breeze/src/airflow_breeze/global_constants.py
@@ -381,6 +381,13 @@ REDIS_HOST_PORT = "26379"
 SSH_PORT = "12322"
 VITE_DEV_PORT = "5173"
 WEB_HOST_PORT = "28080"
+BREEZE_DEBUG_SCHEDULER_PORT = "50231"
+BREEZE_DEBUG_DAG_PROCESSOR_PORT = "50232"
+BREEZE_DEBUG_TRIGGERER_PORT = "50233"
+BREEZE_DEBUG_APISERVER_PORT = "50234"
+BREEZE_DEBUG_CELERY_WORKER_PORT = "50235"
+BREEZE_DEBUG_EDGE_PORT = "50236"
+BREEZE_DEBUG_WEBSERVER_PORT = "50237"
 
 CELERY_BROKER_URLS_MAP = {"rabbitmq": "amqp://guest:guest@rabbitmq:5672", 
"redis": "redis://redis:6379/0"}
 SQLITE_URL = "sqlite:////root/airflow/sqlite/airflow.db"
diff --git a/dev/breeze/src/airflow_breeze/params/shell_params.py 
b/dev/breeze/src/airflow_breeze/params/shell_params.py
index b0fee42cea5..f6bb0bfe174 100644
--- a/dev/breeze/src/airflow_breeze/params/shell_params.py
+++ b/dev/breeze/src/airflow_breeze/params/shell_params.py
@@ -37,6 +37,13 @@ from airflow_breeze.global_constants import (
     ALLOWED_POSTGRES_VERSIONS,
     ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS,
     APACHE_AIRFLOW_GITHUB_REPOSITORY,
+    BREEZE_DEBUG_APISERVER_PORT,
+    BREEZE_DEBUG_CELERY_WORKER_PORT,
+    BREEZE_DEBUG_DAG_PROCESSOR_PORT,
+    BREEZE_DEBUG_EDGE_PORT,
+    BREEZE_DEBUG_SCHEDULER_PORT,
+    BREEZE_DEBUG_TRIGGERER_PORT,
+    BREEZE_DEBUG_WEBSERVER_PORT,
     CELERY_BROKER_URLS_MAP,
     CELERY_EXECUTOR,
     DEFAULT_CELERY_BROKER,
@@ -149,6 +156,8 @@ class ShellParams:
     celery_flower: bool = False
     clean_airflow_installation: bool = False
     collect_only: bool = False
+    debug_components: tuple[str, ...] = ()
+    debugger: str = "debugpy"
     db_reset: bool = False
     default_constraints_branch: str = DEFAULT_AIRFLOW_CONSTRAINTS_BRANCH
     dev_mode: bool = False
@@ -654,12 +663,45 @@ class ShellParams:
         _set_var(_env, "WEB_HOST_PORT", None, WEB_HOST_PORT)
         _set_var(_env, "_AIRFLOW_RUN_DB_TESTS_ONLY", self.run_db_tests_only)
         _set_var(_env, "_AIRFLOW_SKIP_DB_TESTS", self.skip_db_tests)
+
+        self._set_debug_variables(_env)
         self._generate_env_for_docker_compose_file_if_needed(_env)
 
         _target_env: dict[str, str] = os.environ.copy()
         _target_env.update(_env)
         return _target_env
 
+    def _set_debug_variables(self, env) -> None:
+        """Set debug environment variables based on selected debug 
components."""
+        if self.debugger == "pydevd-pycharm":
+            print("Pycharm-pydevd debugger is under development and not yet 
supported in Breeze.")
+            return
+        if not self.debug_components:
+            return
+
+        _set_var(env, "BREEZE_DEBUG_SCHEDULER_PORT", None, 
BREEZE_DEBUG_SCHEDULER_PORT)
+        _set_var(env, "BREEZE_DEBUG_DAG_PROCESSOR_PORT", None, 
BREEZE_DEBUG_DAG_PROCESSOR_PORT)
+        _set_var(env, "BREEZE_DEBUG_TRIGGERER_PORT", None, 
BREEZE_DEBUG_TRIGGERER_PORT)
+        _set_var(env, "BREEZE_DEBUG_APISERVER_PORT", None, 
BREEZE_DEBUG_APISERVER_PORT)
+        _set_var(env, "BREEZE_DEBUG_CELERY_WORKER_PORT", None, 
BREEZE_DEBUG_CELERY_WORKER_PORT)
+        _set_var(env, "BREEZE_DEBUG_EDGE_PORT", None, BREEZE_DEBUG_EDGE_PORT)
+        _set_var(env, "BREEZE_DEBUG_WEBSERVER_PORT", None, 
BREEZE_DEBUG_WEBSERVER_PORT)
+
+        _set_var(env, "BREEZE_DEBUGGER", None, self.debugger)
+
+        component_mappings = {
+            "scheduler": "BREEZE_DEBUG_SCHEDULER",
+            "triggerer": "BREEZE_DEBUG_TRIGGERER",
+            "api-server": "BREEZE_DEBUG_APISERVER",
+            "dag-processor": "BREEZE_DEBUG_DAG_PROCESSOR",
+            "edge-worker": "BREEZE_DEBUG_EDGE",
+            "celery-worker": "BREEZE_DEBUG_CELERY_WORKER",
+        }
+
+        for component in self.debug_components:
+            env_var = component_mappings[component]
+            _set_var(env, env_var, None, "true")
+
     @staticmethod
     def _generate_env_for_docker_compose_file_if_needed(env: dict[str, str]):
         """
diff --git a/scripts/ci/docker-compose/base-ports.yml 
b/scripts/ci/docker-compose/base-ports.yml
index d05771106ea..1e711563896 100644
--- a/scripts/ci/docker-compose/base-ports.yml
+++ b/scripts/ci/docker-compose/base-ports.yml
@@ -21,3 +21,10 @@ services:
       - "${SSH_PORT}:22"
       - "${WEB_HOST_PORT}:8080"
       - "${FLOWER_HOST_PORT}:5555"
+      - "${BREEZE_DEBUG_SCHEDULER_PORT}:50231"
+      - "${BREEZE_DEBUG_DAG_PROCESSOR_PORT}:50232"
+      - "${BREEZE_DEBUG_TRIGGERER_PORT}:50233"
+      - "${BREEZE_DEBUG_APISERVER_PORT}:50234"
+      - "${BREEZE_DEBUG_CELERY_WORKER_PORT}:50235"
+      - "${BREEZE_DEBUG_EDGE_PORT}:50236"
+      - "${BREEZE_DEBUG_WEBSERVER_PORT}:50237"
diff --git a/scripts/in_container/bin/run_tmux 
b/scripts/in_container/bin/run_tmux
index 431fe3faefc..60367737344 100755
--- a/scripts/in_container/bin/run_tmux
+++ b/scripts/in_container/bin/run_tmux
@@ -24,7 +24,7 @@ if [[ ${BACKEND} != "sqlite"  ]]; then
     export AIRFLOW__CORE__EXECUTOR=${AIRFLOW__CORE__EXECUTOR:-LocalExecutor}
 fi
 
-#this is because I run docker in WSL - Hi Nadella!
+
 export TMUX_TMPDIR=~/.tmux/tmp
 if [ -e ~/.tmux/tmp ]; then
     rm -rf ~/.tmux/tmp
@@ -57,22 +57,35 @@ tmux send-keys -t 'Main' 'bash' C-m 'clear' C-m
 
 tmux split-window -v
 tmux select-pane -t 1
+if [[ ${BREEZE_DEBUG_SCHEDULER} == "true" ]]; then
+    tmux set-option -p @airflow_component "Scheduler(Debug Mode)"
+    tmux send-keys "debugpy --listen 0.0.0.0:${BREEZE_DEBUG_SCHEDULER_PORT} 
--wait-for-client -m airflow scheduler" C-m
+else
 tmux set-option -p @airflow_component Scheduler
-tmux send-keys 'airflow scheduler' C-m
+    tmux send-keys "airflow scheduler" C-m
+fi
 
 if [[ ! ${USE_AIRFLOW_VERSION=} =~ ^2\..*  ]]; then
   tmux split-window -h
   tmux select-pane -t 2
+    if [[ ${BREEZE_DEBUG_APISERVER} == "true" ]]; then
+        tmux set-option -p @airflow_component "API Server(Debug Mode)"
+        tmux send-keys "debugpy --listen 
0.0.0.0:${BREEZE_DEBUG_APISERVER_PORT} --wait-for-client -m airflow api-server 
-d" C-m
+    else
   tmux set-option -p @airflow_component "API Server"
-
     if [[ ${DEV_MODE=} == "true" ]]; then
         tmux send-keys 'airflow api-server -d' C-m
     else
         tmux send-keys 'airflow api-server' C-m
     fi
+    fi
 else
   tmux split-window -h
   tmux select-pane -t 3
+    if [[ ${BREEZE_DEBUG_WEBSERVER} == "true" ]]; then
+        tmux set-option -p @airflow_component "Webserver(Debug Mode)"
+        tmux send-keys "debugpy --listen 
0.0.0.0:${BREEZE_DEBUG_WEBSERVER_PORT} --wait-for-client -m airflow webserver" 
C-m
+    else
   tmux set-option -p @airflow_component Webserver
   if [[ ${DEV_MODE=} == "true" ]]; then
       tmux send-keys 'airflow webserver -d' C-m
@@ -80,27 +93,49 @@ else
       tmux send-keys 'airflow webserver' C-m
   fi
 fi
+fi
 
 tmux select-pane -t 0
 tmux split-window -h
+if [[ ${BREEZE_DEBUG_TRIGGERER} == "true" ]]; then
+    tmux set-option -p @airflow_component "Triggerer(Debug Mode)"
+    tmux send-keys "debugpy --listen 0.0.0.0:${BREEZE_DEBUG_TRIGGERER_PORT} 
--wait-for-client -m airflow triggerer" C-m
+else
 tmux set-option -p @airflow_component Triggerer
 tmux send-keys 'airflow triggerer' C-m
+fi
 
 if [[ ${INTEGRATION_CELERY} == "true" ]]; then
     tmux select-pane -t 0
     tmux split-window -h
+    if [[ ${BREEZE_DEBUG_CELERY_WORKER} == "true" ]]; then
+        tmux set-option -p @airflow_component "Celery Worker(Debug Mode)"
+        tmux send-keys "debugpy --listen 
0.0.0.0:${BREEZE_DEBUG_CELERY_WORKER_PORT} --wait-for-client -m airflow celery 
worker" C-m
+    else
     tmux set-option -p @airflow_component "Celery Worker"
     tmux send-keys 'airflow celery worker' C-m
 fi
+fi
+
 if [[ ${INTEGRATION_CELERY} == "true" && ${CELERY_FLOWER} == "true" ]]; then
     tmux select-pane -t 3
     tmux split-window -h
+    if [[ ${BREEZE_DEBUG_FLOWER} == "true" ]]; then
+        tmux set-option -p @airflow_component "Flower(Debug Mode)"
+        tmux send-keys "debugpy --listen 0.0.0.0:${BREEZE_DEBUG_FLOWER_PORT} 
--wait-for-client -m airflow celery flower" C-m
+    else
     tmux set-option -p @airflow_component Flower
     tmux send-keys 'airflow celery flower' C-m
 fi
+fi
+
 if [[ ${AIRFLOW__CORE__EXECUTOR} == 
"airflow.providers.edge3.executors.edge_executor.EdgeExecutor" ]]; then
     tmux select-pane -t 0
     tmux split-window -h
+    if [[ ${BREEZE_DEBUG_EDGE} == "true" ]]; then
+        tmux set-option -p @airflow_component "Edge Worker(Debug Mode)"
+        tmux send-keys "debugpy --listen 0.0.0.0:${BREEZE_DEBUG_EDGE_PORT} 
--wait-for-client -m airflow edge worker --edge-hostname breeze --queues 
default" C-m
+    else
     tmux set-option -p @airflow_component "Edge Worker"
 
     # Ensure we are not leaking any DB connection information to Edge Worker 
process
@@ -116,12 +151,19 @@ if [[ ${AIRFLOW__CORE__EXECUTOR} == 
"airflow.providers.edge3.executors.edge_exec
     # Start Edge Worker and make a "breeze" hostname, let it pick only default 
queue
     tmux send-keys 'airflow edge worker --edge-hostname breeze --queues 
default' C-m
 fi
+fi
+
 if [[ ${STANDALONE_DAG_PROCESSOR} == "true" ]]; then
     tmux select-pane -t 3
     tmux split-window -h
+    if [[ ${BREEZE_DEBUG_DAG_PROCESSOR} == "true" ]]; then
+        tmux set-option -p @airflow_component "DAG Processor(Debug Mode)"
+        tmux send-keys "debugpy --listen 
0.0.0.0:${BREEZE_DEBUG_DAG_PROCESSOR_PORT} --wait-for-client -m airflow 
dag-processor" C-m
+    else
     tmux set-option -p @airflow_component "DAG Processor"
     tmux send-keys 'airflow dag-processor' C-m
 fi
+fi
 
 # Attach Session, on the Main window
 tmux select-pane -t 0
diff --git a/setup_vscode.py b/setup_vscode.py
new file mode 100755
index 00000000000..56b53f6fd93
--- /dev/null
+++ b/setup_vscode.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# /// script
+# requires-python = ">=3.10"
+# dependencies = [
+#   "rich>=13.6.0",
+# ]
+# ///
+from __future__ import annotations
+
+import json
+from pathlib import Path
+
+from rich import print
+from rich.prompt import Confirm
+
+# Debug port mappings for Airflow components
+DEBUG_PORTS = {
+    "scheduler": 50231,
+    "dag-processor": 50232,
+    "triggerer": 50233,
+    "api-server": 50234,
+    "celery-worker": 50235,
+    "edge-worker": 50236,
+}
+
+# Component descriptions for better naming
+COMPONENT_NAMES = {
+    "scheduler": "Scheduler",
+    "dag-processor": "DAG Processor",
+    "triggerer": "Triggerer",
+    "api-server": "API Server",
+    "celery-worker": "Celery Worker",
+    "edge-worker": "Edge Worker",
+}
+
+ROOT_AIRFLOW_FOLDER_PATH = Path(__file__).parent
+VSCODE_FOLDER_PATH = ROOT_AIRFLOW_FOLDER_PATH / ".vscode"
+LAUNCH_JSON_FILE = VSCODE_FOLDER_PATH / "launch.json"
+
+
+def create_debug_configuration(component: str, port: int) -> dict:
+    """Create a debug configuration for a specific Airflow component."""
+    return {
+        "name": f"Debug Airflow {COMPONENT_NAMES[component]}",
+        "type": "debugpy",
+        "request": "attach",
+        "justMyCode": False,
+        "connect": {"host": "localhost", "port": port},
+        "pathMappings": [{"localRoot": "${workspaceFolder}", "remoteRoot": 
"/opt/airflow"}],
+    }
+
+
+def create_launch_json_content() -> dict:
+    """Create the complete launch.json content with all debug 
configurations."""
+    configurations = []
+
+    for component, port in DEBUG_PORTS.items():
+        config = create_debug_configuration(component, port)
+        configurations.append(config)
+
+    return {"version": "0.2.0", "configurations": configurations}
+
+
+def setup_vscode():
+    """Set up VSCode debug configurations for Airflow components."""
+    print("[green]Creating[/] VSCode debug configurations for Airflow 
components...")
+
+    # Create configurations for each component
+    for component, port in DEBUG_PORTS.items():
+        print(f"[green]Adding[/] debug configuration: 
[blue]{COMPONENT_NAMES[component]}[/] (port {port})")
+
+    # Create the launch.json content
+    launch_json_content = create_launch_json_content()
+
+    # Ensure .vscode directory exists
+    VSCODE_FOLDER_PATH.mkdir(exist_ok=True)
+
+    # Write the launch.json file
+    with open(LAUNCH_JSON_FILE, "w") as f:
+        json.dump(launch_json_content, f, indent=4)
+
+    print(f"\n[green]Successfully created[/] {LAUNCH_JSON_FILE}")
+
+
+def main():
+    print("\n[yellow]VSCode Airflow Debug Configuration Setup[/]\n")
+    print("This script will create VSCode debug configurations for Airflow 
components:\n")
+
+    for component, port in DEBUG_PORTS.items():
+        print(f"* {COMPONENT_NAMES[component]}: port {port}")
+
+    print(f"\nConfiguration will be written to: {LAUNCH_JSON_FILE}")
+
+    if LAUNCH_JSON_FILE.exists():
+        print(f"\n[yellow]Warning:[/] {LAUNCH_JSON_FILE} already exists!")
+        should_overwrite = Confirm.ask("Overwrite the existing file?")
+        if not should_overwrite:
+            print("[yellow]Skipped[/] - No changes made")
+            return
+    else:
+        should_continue = Confirm.ask("Create the debug configurations?")
+        if not should_continue:
+            print("[yellow]Skipped[/] - No changes made")
+            return
+
+    setup_vscode()
+
+    print("\n[green]Setup complete![/]")
+    print("\nFor more information, see: 
contributing-docs/20_debugging_airflow_components.rst")
+
+
+if __name__ == "__main__":
+    main()


Reply via email to