""" Weibo-HotSign Sign-in Task Definitions Celery tasks for scheduled sign-in operations """ import asyncio import httpx import json import logging from datetime import datetime from typing import Dict, Any, Optional from celery import current_task from ..celery_app import celery_app from ..config import settings # Configure logger logger = logging.getLogger(__name__) @celery_app.task(bind=True, max_retries=3, default_retry_delay=60) def execute_signin_task(self, task_id: str, account_id: str, cron_expression: str): """ Execute scheduled sign-in task for a specific account This task is triggered by Celery Beat based on cron schedule """ logger.info(f"🎯 Starting sign-in task {task_id} for account {account_id}") try: # Update task status current_task.update_state( state="PROGRESS", meta={ "current": 10, "total": 100, "status": "Initializing sign-in process...", "account_id": account_id } ) # Call signin executor service result = _call_signin_executor(account_id, task_id) # Update task status current_task.update_state( state="SUCCESS", meta={ "current": 100, "total": 100, "status": "Sign-in completed successfully", "result": result, "account_id": account_id } ) logger.info(f"✅ Sign-in task {task_id} completed successfully for account {account_id}") return result except Exception as exc: logger.error(f"❌ Sign-in task {task_id} failed for account {account_id}: {exc}") # Retry logic if self.request.retries < settings.MAX_RETRY_ATTEMPTS: logger.info(f"🔄 Retrying task {task_id} (attempt {self.request.retries + 1})") raise self.retry(exc=exc, countdown=settings.RETRY_DELAY_SECONDS) # Final failure current_task.update_state( state="FAILURE", meta={ "current": 100, "total": 100, "status": f"Task failed after {settings.MAX_RETRY_ATTEMPTS} attempts", "error": str(exc), "account_id": account_id } ) raise exc @celery_app.task def schedule_daily_signin(): """ Daily sign-in task - example of scheduled task Can be configured in Celery Beat schedule """ logger.info("📅 Executing daily sign-in schedule") # This would typically query database for accounts that need daily sign-in # For demo purposes, we'll simulate processing multiple accounts accounts = ["account_1", "account_2", "account_3"] # Mock account IDs results = [] for account_id in accounts: try: # Submit individual sign-in task for each account task = execute_signin_task.delay( task_id=f"daily_{datetime.now().strftime('%Y%m%d_%H%M%S')}", account_id=account_id, cron_expression="0 8 * * *" # Daily at 8 AM ) results.append({ "account_id": account_id, "task_id": task.id, "status": "submitted" }) except Exception as e: logger.error(f"Failed to submit task for account {account_id}: {e}") results.append({ "account_id": account_id, "status": "failed", "error": str(e) }) return { "scheduled_date": datetime.now().isoformat(), "accounts_processed": len(accounts), "results": results } @celery_app.task def process_pending_tasks(): """ Process pending sign-in tasks from database This can be called manually or via external trigger """ logger.info("🔄 Processing pending sign-in tasks from database") # In real implementation, this would: # 1. Query database for tasks that need to be executed # 2. Check if they're due based on cron expressions # 3. Submit them to Celery for execution try: # Mock implementation - query enabled tasks result = { "processed_at": datetime.now().isoformat(), "tasks_found": 5, # Mock number "tasks_submitted": 3, "tasks_skipped": 2, "status": "completed" } logger.info(f"✅ Processed pending tasks: {result}") return result except Exception as e: logger.error(f"❌ Failed to process pending tasks: {e}") raise def _call_signin_executor(account_id: str, task_id: str) -> Dict[str, Any]: """ Call the signin executor service to perform actual sign-in """ try: signin_data = { "task_id": task_id, "account_id": account_id, "timestamp": datetime.now().isoformat(), "requested_by": "task_scheduler" } # Call signin executor service with httpx.Client(timeout=30.0) as client: response = client.post( f"{settings.SIGNIN_EXECUTOR_URL}/api/v1/signin/execute", json=signin_data ) if response.status_code == 200: result = response.json() logger.info(f"Sign-in executor response: {result}") return result else: raise Exception(f"Sign-in executor returned error: {response.status_code} - {response.text}") except httpx.RequestError as e: logger.error(f"Network error calling signin executor: {e}") raise Exception(f"Failed to connect to signin executor: {e}") except Exception as e: logger.error(f"Error calling signin executor: {e}") raise # Periodic task definitions for Celery Beat celery_app.conf.beat_schedule = { "daily-signin-at-8am": { "task": "app.tasks.signin_tasks.schedule_daily_signin", "schedule": { "hour": 8, "minute": 0, }, }, "process-pending-every-15-minutes": { "task": "app.tasks.signin_tasks.process_pending_tasks", "schedule": 900.0, # Every 15 minutes }, }