Skip to main content

apache-airflow-orchestration

Expert knowledge of Apache Airflow for building, scheduling, and monitoring data pipelines and workflows

معلومات المصدر

المستودع
reason-machines/data-skills
آخر نشاط في المصدر
١٦ مايو ٢٠٢٦ في ١٤:٣٧
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
apache-airflow-orchestration
description
Expert knowledge of Apache Airflow for building, scheduling, and monitoring data pipelines and workflows
triggers
["how do I create an Airflow DAG","help me schedule a workflow in Airflow","how to set up Apache Airflow","create an Airflow pipeline","how do I use Airflow operators","troubleshoot Airflow task failures","configure Airflow connections","how to use XCom in Airflow"]
# Apache Airflow Orchestration > Skill by [ara.so](https://ara.so) — Data Skills collection. Apache Airflow is a platform to programmatically author, schedule, and monitor workflows. It allows you to define workflows as Directed Acyclic Graphs (DAGs) in Python code, making them maintainable, versionable, testable, and collaborative. ## Installation ### Using pip ```bash # Install Airflow with constraints for your Python version AIRFLOW_VERSION=3.2.0 PYTHON_VERSION="$(python --version | cut -d " " -f 2 | cut -d "." -f 1-2)" CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt" pip install "apache-airflow==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}" ``` ### Using Docker (Recommended for Development) ```bash # Download docker-compose.yaml curl -LfO 'https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml' # Create required directories mkdir -p ./dags ./logs ./plugins ./config # Set the Airflow user echo -e "AIRFLOW_UID=$(id -u)" > .env # Initialize the database docker compose up airflow-init # Start Airflow docker compose up ``` Access the web UI at `http://localhost:8080` (default credentials: `airflow`/`airflow`). ### Standalone Quick Start ```bash # Initialize database and create admin user airflow db init # Create admin user airflow users create \ --username admin \ --firstname Admin \ --lastname User \ --role Admin \ --email admin@example.com # Start the web server (default port 8080) airflow webserver --port 8080 # Start the scheduler (in another terminal) airflow scheduler ``` ## Core Concepts ### DAG (Directed Acyclic Graph) A DAG defines a workflow with tasks and their dependencies. Tasks must not create cycles. ### Basic DAG Structure ```python from datetime import datetime, timedelta from airflow import DAG from airflow.operators.python import PythonOperator from airflow.operators.bash import BashOperator # Default arguments applied to all tasks default_args = { 'owner': 'data-team', 'depends_on_past': False, 'email': ['alerts@example.com'], 'email_on_failure': True, 'email_on_retry': False, 'retries': 3, 'retry_delay': timedelta(minutes=5), } # Define the DAG dag = DAG( 'example_data_pipeline', default_args=default_args, description='A simple data pipeline', schedule='0 0 * * *', # Run daily at midnight (cron expression) start_date=datetime(2024, 1, 1), catchup=False, # Don't run for past dates tags=['example', 'data-engineering'], ) def extract_data(**context): """Extract data from source""" print("Extracting data...") # Your extraction logic here return {'records': 1000} def transform_data(**context): """Transform extracted data""" # Access data from previous task via XCom ti = context['ti'] extracted = ti.xcom_pull(task_ids='extract') print(f"Transforming {extracted['records']} records...") return {'transformed_records': extracted['records']} def load_data(**context): """Load data to destination""" ti = context['ti'] transformed = ti.xcom_pull(task_ids='transform') print(f"Loading {transformed['transformed_records']} records...") # Define tasks extract = PythonOperator( task_id='extract', python_callable=extract_data, dag=dag, ) transform = PythonOperator( task_id='transform', python_callable=transform_data, dag=dag, ) load = PythonOperator( task_id='load', python_callable=load_data, dag=dag, ) # Set task dependencies extract >> transform >> load ``` ### TaskFlow API (Recommended for Airflow 2.0+) Modern, cleaner syntax using decorators: ```python from datetime import datetime from airflow.decorators import dag, task @dag( schedule='@daily', start_date=datetime(2024, 1, 1), catchup=False, tags=['taskflow', 'etl'], ) def taskflow_etl_pipeline(): """ ETL pipeline using TaskFlow API """ @task() def extract(): """Extract data from API""" import requests # Using environment variable for API key import os api_key = os.getenv('DATA_API_KEY') # Simulated extraction data = {'records': [1, 2, 3, 4, 5]} return data @task() def transform(data: dict): """Transform the data""" records = data['records'] transformed = [r * 2 for r in records] return {'transformed': transformed} @task() def load(data: dict): """Load data to warehouse""" print(f"Loading {len(data['transformed'])} records") # Your loading logic here return True # Define pipeline extracted_data = extract() transformed_data = transform(extracted_data) load(transformed_data) # Instantiate the DAG taskflow_etl_pipeline() ``` ## Common Operators ### BashOperator ```python from airflow.operators.bash import BashOperator run_script = BashOperator( task_id='run_data_script', bash_command='python /opt/scripts/process_data.py --date {{ ds }}', dag=dag, ) ``` ### PythonOperator ```python from airflow.operators.python import PythonOperator def my_function(param1, param2, **context): execution_date = context['execution_date'] print(f"Processing for {execution_date}") # Your logic here python_task = PythonOperator( task_id='python_task', python_callable=my_function, op_kwargs={'param1': 'value1', 'param2': 'value2'}, dag=dag, ) ``` ### BranchPythonOperator ```python from airflow.operators.python import BranchPythonOperator from airflow.operators.empty import EmptyOperator def choose_branch(**context): """Decide which branch to execute""" execution_date = context['execution_date'] if execution_date.day % 2 == 0: return 'even_day_task' else: return 'odd_day_task' branch = BranchPythonOperator( task_id='branch_task', python_callable=choose_branch, dag=dag, ) even_task = EmptyOperator(task_id='even_day_task', dag=dag) odd_task = EmptyOperator(task_id='odd_day_task', dag=dag) branch >> [even_task, odd_task] ``` ### EmailOperator ```python from airflow.operators.email import EmailOperator send_email = EmailOperator( task_id='send_notification', to='team@example.com', subject='Pipeline {{ ds }} completed', html_content='<p>The pipeline for {{ ds }} has completed successfully.</p>', dag=dag, ) ``` ## Sensors Sensors wait for a condition to be met before proceeding. ### FileSensor ```python from airflow.sensors.filesystem import FileSensor wait_for_file = FileSensor( task_id='wait_for_data_file', filepath='/data/input/file_{{ ds }}.csv', poke_interval=30, # Check every 30 seconds timeout=3600, # Timeout after 1 hour mode='poke', # 'poke' or 'reschedule' dag=dag, ) ``` ### TimeDeltaSensor ```python from airflow.sensors.time_delta import TimeDeltaSensor from datetime import timedelta wait_sensor = TimeDeltaSensor( task_id='wait_10_minutes', delta=timedelta(minutes=10), dag=dag, ) ``` ### Custom Sensor ```python from airflow.sensors.base import BaseSensorOperator class CustomDataSensor(BaseSensorOperator): def __init__(self, endpoint, **kwargs): super().__init__(**kwargs) self.endpoint = endpoint def poke(self, context): """Check if data is available""" import requests import os api_key = os.getenv('API_KEY') response = requests.get( self.endpoint, headers={'Authorization': f'Bearer {api_key}'} ) return response.status_code == 200 and response.json().get('ready', False) check_data = CustomDataSensor( task_id='check_data_ready', endpoint='https://api.example.com/status', poke_interval=60, timeout=3600, dag=dag, ) ``` ## Connections and Hooks ### Setting Up Connections Connections store credentials and connection details. #### Via CLI ```bash # Add a Postgres connection airflow connections add 'postgres_default' \ --conn-type 'postgres' \ --conn-host 'localhost' \ --conn-schema 'mydb' \ --conn-login 'user' \ --conn-password 'password' \ --conn-port 5432 # Add an HTTP connection airflow connections add 'http_api' \ --conn-type 'http' \ --conn-host 'https://api.example.com' \ --conn-extra '{"api_key": "from_env_var"}' ``` #### Via Environment Variables ```bash export AIRFLOW_CONN_POSTGRES_DEFAULT='postgresql://user:password@localhost:5432/mydb' export AIRFLOW_CONN_HTTP_API='http://api.example.com' ``` ### Using Hooks ```python from airflow.providers.postgres.hooks.postgres import PostgresHook from airflow.decorators import task @task() def query_database(): """Query PostgreSQL database""" hook = PostgresHook(postgres_conn_id='postgres_default') # Execute query and fetch results results = hook.get_records( sql="SELECT * FROM users WHERE created_date = %s", parameters=['2024-01-01'] ) # Or use pandas df = hook.get_pandas_df(sql="SELECT * FROM transactions") return len(results) @task() def insert_data(): """Insert data into database""" hook = PostgresHook(postgres_conn_id='postgres_default') hook.run( sql="INSERT INTO logs (message, timestamp) VALUES (%s, %s)", parameters=[('Pipeline completed', datetime.now())] ) ``` ### HTTP Hook Example ```python from airflow.providers.http.hooks.http import HttpHook from airflow.decorators import task @task() def call_api(): """Make HTTP API call""" hook = HttpHook(http_conn_id='http_api', method='GET') response = hook.run( endpoint='/v1/data', headers={'Content-Type': 'application/json'}, extra_options={'timeout': 30} ) data = response.json() return data ``` ## XCom (Cross-Communication) XCom allows tasks to exchange small amounts of data. ```python from airflow.decorators import dag, task from datetime import datetime @dag(start_date=datetime(2024, 1, 1), schedule=None, catchup=False) def xcom_example(): @task() def push_data(): """Push data to XCom""" return { 'total_records': 1000, 'processing_time': 45.2, 'status': 'success' } @task() def pull_data(data: dict): """Receive data from previous task""" print(f"Received {data['total_records']} records") print(f"Processing took {data['processing_time']} seconds") # Can also use task instance to pull from specific task from airflow.operators.python import get_current_context context = get_current_context() ti = context['ti'] # Pull from specific task specific_data = ti.xcom_pull(task_ids='push_data') return specific_data['status']
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub