Updated due to different af-green install issues

This commit is contained in:
aperez 2025-11-24 10:22:22 +03:00
parent 451f349904
commit 302282365e
9 changed files with 109 additions and 53 deletions

View File

@ -592,8 +592,20 @@ def manage_system_callable(**context):
if not account_id: raise ValueError("An 'account_id' is required.") if not account_id: raise ValueError("An 'account_id' is required.")
reason = f"Manual un-ban from Airflow mgmt DAG by {socket.gethostname()}" reason = f"Manual un-ban from Airflow mgmt DAG by {socket.gethostname()}"
logger.info(f"Unbanning account '{account_id}'...") logger.info(f"Unbanning account '{account_id}'...")
# Fetch status to get current success count before unbanning
statuses = client.getAccountStatus(accountId=account_id, accountPrefix=None)
if not statuses:
raise AirflowException(f"Account '{account_id}' not found.")
current_success_count = statuses[0].successCount or 0
client.unbanAccount(accountId=account_id, reason=reason) client.unbanAccount(accountId=account_id, reason=reason)
print(f"Successfully sent request to unban account '{account_id}'.") print(f"Successfully sent request to unban account '{account_id}'.")
# Set the success_count_at_activation to baseline the account
redis_client = _get_redis_client(params["redis_conn_id"])
redis_client.hset(f"account_status:{account_id}", "success_count_at_activation", current_success_count)
logger.info(f"Set 'success_count_at_activation' for '{account_id}' to {current_success_count}.")
elif action == "unban_all": elif action == "unban_all":
account_prefix = account_id # Repurpose account_id param as an optional prefix account_prefix = account_id # Repurpose account_id param as an optional prefix
logger.info(f"Unbanning all account statuses to ACTIVE (prefix: '{account_prefix or 'ALL'}')...") logger.info(f"Unbanning all account statuses to ACTIVE (prefix: '{account_prefix or 'ALL'}')...")
@ -604,6 +616,9 @@ def manage_system_callable(**context):
return return
accounts_to_unban = [s.accountId for s in all_statuses] accounts_to_unban = [s.accountId for s in all_statuses]
account_map = {s.accountId: s for s in all_statuses}
redis_client = _get_redis_client(params["redis_conn_id"])
logger.info(f"Found {len(accounts_to_unban)} accounts to unban.") logger.info(f"Found {len(accounts_to_unban)} accounts to unban.")
print(f"Found {len(accounts_to_unban)} accounts. Sending unban request for each...") print(f"Found {len(accounts_to_unban)} accounts. Sending unban request for each...")
@ -614,6 +629,12 @@ def manage_system_callable(**context):
reason = f"Manual unban_all from Airflow mgmt DAG by {socket.gethostname()}" reason = f"Manual unban_all from Airflow mgmt DAG by {socket.gethostname()}"
client.unbanAccount(accountId=acc_id, reason=reason) client.unbanAccount(accountId=acc_id, reason=reason)
logger.info(f" - Sent unban for '{acc_id}'.") logger.info(f" - Sent unban for '{acc_id}'.")
# Also set the success_count_at_activation to baseline the account
current_success_count = account_map[acc_id].successCount or 0
redis_client.hset(f"account_status:{acc_id}", "success_count_at_activation", current_success_count)
logger.info(f" - Set 'success_count_at_activation' for '{acc_id}' to {current_success_count}.")
unban_count += 1 unban_count += 1
except Exception as e: except Exception as e:
logger.error(f" - Failed to unban account '{acc_id}': {e}") logger.error(f" - Failed to unban account '{acc_id}': {e}")
@ -729,8 +750,20 @@ def manage_system_callable(**context):
if not account_id: raise ValueError("An 'account_id' is required.") if not account_id: raise ValueError("An 'account_id' is required.")
reason = f"Manual un-ban from Airflow mgmt DAG by {socket.gethostname()}" reason = f"Manual un-ban from Airflow mgmt DAG by {socket.gethostname()}"
logger.info(f"Unbanning account '{account_id}'...") logger.info(f"Unbanning account '{account_id}'...")
# Fetch status to get current success count before unbanning
statuses = client.getAccountStatus(accountId=account_id, accountPrefix=None)
if not statuses:
logger.warning(f"Account '{account_id}' not found. Skipping account unban.")
else:
current_success_count = statuses[0].successCount or 0
client.unbanAccount(accountId=account_id, reason=reason) client.unbanAccount(accountId=account_id, reason=reason)
print(f"Successfully sent request to unban account '{account_id}'.") print(f"Successfully sent request to unban account '{account_id}'.")
# Set the success_count_at_activation to baseline the account
redis_client = _get_redis_client(params["redis_conn_id"])
redis_client.hset(f"account_status:{account_id}", "success_count_at_activation", current_success_count)
logger.info(f"Set 'success_count_at_activation' for '{account_id}' to {current_success_count}.")
elif action == "unban_all": elif action == "unban_all":
account_prefix = account_id # Repurpose account_id param as an optional prefix account_prefix = account_id # Repurpose account_id param as an optional prefix
logger.info(f"Unbanning all account statuses to ACTIVE (prefix: '{account_prefix or 'ALL'}')...") logger.info(f"Unbanning all account statuses to ACTIVE (prefix: '{account_prefix or 'ALL'}')...")
@ -740,6 +773,9 @@ def manage_system_callable(**context):
print(f"No accounts found with prefix '{account_prefix or 'ALL'}' to unban.") print(f"No accounts found with prefix '{account_prefix or 'ALL'}' to unban.")
else: else:
accounts_to_unban = [s.accountId for s in all_statuses] accounts_to_unban = [s.accountId for s in all_statuses]
account_map = {s.accountId: s for s in all_statuses}
redis_client = _get_redis_client(params["redis_conn_id"])
logger.info(f"Found {len(accounts_to_unban)} accounts to unban.") logger.info(f"Found {len(accounts_to_unban)} accounts to unban.")
print(f"Found {len(accounts_to_unban)} accounts. Sending unban request for each...") print(f"Found {len(accounts_to_unban)} accounts. Sending unban request for each...")
@ -750,6 +786,12 @@ def manage_system_callable(**context):
reason = f"Manual unban_all from Airflow mgmt DAG by {socket.gethostname()}" reason = f"Manual unban_all from Airflow mgmt DAG by {socket.gethostname()}"
client.unbanAccount(accountId=acc_id, reason=reason) client.unbanAccount(accountId=acc_id, reason=reason)
logger.info(f" - Sent unban for '{acc_id}'.") logger.info(f" - Sent unban for '{acc_id}'.")
# Also set the success_count_at_activation to baseline the account
current_success_count = account_map[acc_id].successCount or 0
redis_client.hset(f"account_status:{acc_id}", "success_count_at_activation", current_success_count)
logger.info(f" - Set 'success_count_at_activation' for '{acc_id}' to {current_success_count}.")
unban_count += 1 unban_count += 1
except Exception as e: except Exception as e:
logger.error(f" - Failed to unban account '{acc_id}': {e}") logger.error(f" - Failed to unban account '{acc_id}': {e}")

View File

@ -19,6 +19,7 @@ from airflow.models.param import Param
from airflow.operators.python import PythonOperator, BranchPythonOperator from airflow.operators.python import PythonOperator, BranchPythonOperator
from airflow.operators.empty import EmptyOperator from airflow.operators.empty import EmptyOperator
from airflow.operators.bash import BashOperator from airflow.operators.bash import BashOperator
from airflow.providers.celery.executors.celery_executor import app as celery_app
from airflow.providers.redis.hooks.redis import RedisHook from airflow.providers.redis.hooks.redis import RedisHook
from airflow.utils.dates import days_ago from airflow.utils.dates import days_ago
from airflow.models.variable import Variable from airflow.models.variable import Variable
@ -535,6 +536,45 @@ def requeue_failed_callable(**context):
raise AirflowException(f"Failed to requeue failed URLs: {e}") raise AirflowException(f"Failed to requeue failed URLs: {e}")
def purge_celery_queue_callable(**context):
"""
Purges messages from the specified Celery queues using the Airflow Celery app.
This is more reliable than shelling out to `celery purge` as it uses the same
app context and broker connection as the workers.
"""
params = context['params']
if not params.get('confirm_purge'):
raise AirflowException("'Confirm Purge' is not checked. Aborting to prevent accidental data loss.")
queues_to_purge_str = params.get('celery_queue_to_purge')
if not queues_to_purge_str:
raise AirflowException("No Celery queues specified to purge.")
queues = [q.strip() for q in queues_to_purge_str.split(',') if q.strip()]
logger.info(f"Attempting to purge {len(queues)} Celery queue(s): {queues}")
logger.info(f"Using broker: {celery_app.conf.broker_url}")
purged_counts = {}
with celery_app.connection_for_read() as conn:
with conn.channel() as channel:
for queue in queues:
try:
message_count = channel.queue_purge(queue)
purged_counts[queue] = message_count
logger.info(f"Purged {message_count} messages from queue '{queue}'.")
except Exception as e:
# This can happen if the queue doesn't exist on the broker.
# kombu might raise an operational error.
logger.error(f"Failed to purge queue '{queue}': {e}", exc_info=True)
purged_counts[queue] = f"ERROR: {e}"
logger.info("--- Celery Purge Summary ---")
for queue, result in purged_counts.items():
logger.info(f" - {queue}: {result}")
logger.info("--- Purge complete. ---")
def add_videos_to_queue_callable(**context): def add_videos_to_queue_callable(**context):
""" """
Parses video inputs from manual text, a predefined file, or a file path/URL, Parses video inputs from manual text, a predefined file, or a file path/URL,
@ -821,32 +861,9 @@ with DAG(
""", """,
) )
action_purge_celery_queue = BashOperator( action_purge_celery_queue = PythonOperator(
task_id="action_purge_celery_queue", task_id="action_purge_celery_queue",
bash_command=""" python_callable=purge_celery_queue_callable,
if [ "{{ params.confirm_purge }}" != "True" ]; then
echo "ERROR: 'Confirm Purge' is not checked. Aborting to prevent accidental data loss."
exit 1
fi
BROKER_URL=$(airflow config get-value celery broker_url)
QUEUES_TO_PURGE="{{ params.celery_queue_to_purge }}"
if [ -z "$QUEUES_TO_PURGE" ]; then
echo "ERROR: No Celery queues specified to purge."
exit 1
fi
echo "--- Purging Celery Queues (Broker: $BROKER_URL) ---"
# Use tr to convert comma-separated string to space-separated for the loop
for Q in $(echo $QUEUES_TO_PURGE | tr ',' ' '); do
echo "Purging queue: $Q"
celery -A airflow.providers.celery.executors.celery_executor.app -b "$BROKER_URL" purge -f -Q "$Q"
done
echo "--- Purge command sent for all specified queues. ---"
""",
) )
# --- Wire up tasks --- # --- Wire up tasks ---

View File

@ -147,10 +147,17 @@ def manage_account_states(**context):
logger.info("--- Step 3: Processing un-bans ---") logger.info("--- Step 3: Processing un-bans ---")
if accounts_to_unban: if accounts_to_unban:
logger.info(f"Un-banning {len(accounts_to_unban)} accounts: {accounts_to_unban}") logger.info(f"Un-banning {len(accounts_to_unban)} accounts: {accounts_to_unban}")
account_map = {acc.accountId: acc for acc in all_accounts}
for acc_id in accounts_to_unban: for acc_id in accounts_to_unban:
try: try:
client.unbanAccount(acc_id, "Automatic un-ban by Airflow maintenance DAG.") client.unbanAccount(acc_id, "Automatic un-ban by Airflow maintenance DAG.")
logger.info(f"Successfully un-banned account '{acc_id}'.") logger.info(f"Successfully un-banned account '{acc_id}'.")
# Set the activation count to baseline the account immediately after un-banning.
key = f"account_status:{acc_id}"
current_success_count = account_map[acc_id].successCount or 0
redis_client.hset(key, "success_count_at_activation", current_success_count)
logger.info(f"Set 'success_count_at_activation' for un-banned account '{acc_id}' to {current_success_count}.")
except Exception as e: except Exception as e:
logger.error(f"Failed to un-ban account '{acc_id}': {e}") logger.error(f"Failed to un-ban account '{acc_id}': {e}")
else: else:

View File

@ -25,7 +25,6 @@
- thrift - thrift
- aria2p - aria2p
- PyYAML - PyYAML
- apache-airflow-providers-amazon
state: present state: present
become: yes become: yes
@ -279,20 +278,23 @@
var: config_generator_result.stdout_lines var: config_generator_result.stdout_lines
when: config_generator_result.changed when: config_generator_result.changed
- name: Start ytdlp-ops services on master
community.docker.docker_compose_v2:
project_src: "{{ airflow_master_dir }}"
files:
- configs/docker-compose-ytdlp-ops.yaml
state: present
remove_orphans: true
pull: "{{ 'never' if fast_deploy | default(false) else 'missing' }}"
roles: roles:
- ytdlp-master - ytdlp-master
- airflow-master - airflow-master
post_tasks: post_tasks:
- name: Wait for airflow-scheduler to be running before proceeding
ansible.builtin.command: docker compose ps --filter "status=running" --services
args:
chdir: "{{ airflow_master_dir }}"
register: running_services
until: "'airflow-scheduler' in running_services.stdout_lines"
retries: 30
delay: 10
changed_when: false
become: yes
become_user: "{{ ansible_user }}"
- name: Delete existing Airflow redis_default connection to ensure an idempotent update - name: Delete existing Airflow redis_default connection to ensure an idempotent update
ansible.builtin.command: > ansible.builtin.command: >
docker compose exec -T airflow-scheduler docker compose exec -T airflow-scheduler

View File

@ -102,13 +102,7 @@
dest: "{{ airflow_worker_dir }}/{{ item }}" dest: "{{ airflow_worker_dir }}/{{ item }}"
perms: yes perms: yes
loop: loop:
- "README.client.md"
- "cli.config" - "cli.config"
- "format_download.py"
- "get_info_json_client.py"
- "list_formats.py"
- "stress_test_formats.py"
- "stress_enhanced.py"
- "package_client.py" - "package_client.py"
- "bin/ytops-client" - "bin/ytops-client"
become: yes become: yes

View File

@ -1,9 +1,10 @@
--- ---
- name: Update S3 Delivery Airflow Connection - name: Update S3 Connection Variable
hosts: airflow_master hosts: airflow_master
gather_facts: no
vars_files: vars_files:
- "{{ inventory_dir }}/group_vars/all/vault.yml"
- "{{ inventory_dir }}/group_vars/all/generated_vars.yml" - "{{ inventory_dir }}/group_vars/all/generated_vars.yml"
- "{{ inventory_dir }}/group_vars/all/vault.yml"
tasks: tasks:
- name: Delete existing s3_delivery_connection to ensure an idempotent update - name: Delete existing s3_delivery_connection to ensure an idempotent update
ansible.builtin.command: > ansible.builtin.command: >

View File

@ -17,12 +17,6 @@
mode: '0755' mode: '0755'
become: yes become: yes
- name: "Copy get_info_json_client.py to worker"
ansible.builtin.copy:
src: ../../get_info_json_client.py
dest: "{{ project_dir }}/get_info_json_client.py"
mode: '0755'
become: yes
- name: "Pull the latest image for the ytdlp-ops service" - name: "Pull the latest image for the ytdlp-ops service"
community.docker.docker_image: community.docker.docker_image:

View File

@ -81,7 +81,6 @@
- "thrift_model" - "thrift_model"
- "VERSION" - "VERSION"
- "airflow/update-yt-dlp.sh" - "airflow/update-yt-dlp.sh"
- "get_info_json_client.py"
- "proxy_manager_client.py" - "proxy_manager_client.py"
- "utils" - "utils"
@ -328,6 +327,7 @@
project_src: "{{ airflow_master_dir }}" project_src: "{{ airflow_master_dir }}"
files: files:
- "configs/docker-compose-master.yaml" - "configs/docker-compose-master.yaml"
- "configs/docker-compose-ytdlp-ops.yaml"
state: present state: present
remove_orphans: true remove_orphans: true
pull: "{{ 'never' if fast_deploy | default(false) else 'missing' }}" pull: "{{ 'never' if fast_deploy | default(false) else 'missing' }}"

View File

@ -71,7 +71,6 @@
- "thrift_model" - "thrift_model"
- "VERSION" - "VERSION"
- "airflow/update-yt-dlp.sh" - "airflow/update-yt-dlp.sh"
- "get_info_json_client.py"
- "proxy_manager_client.py" - "proxy_manager_client.py"
- "utils" - "utils"