
    di/                        U d Z ddlZddlZddlZddlmZmZ ddlmZmZm	Z	m
Z
mZ ddlmZ ddlmZ  ej                   e      Z G d dee      Zej*                  g ej,                  g ej.                  ej*                  gej0                  ej*                  gej2                  ej,                  ej*                  giZeeee   f   ed	<   ej*                  d
ej,                  d
ej.                  dej0                  dej2                  diZeeef   ed<   ej*                  gej*                  gej*                  gej*                  gej,                  gej,                  gej,                  gej,                  gej,                  gej,                  gej,                  gej,                  gdZeeee   f   ed<   ej*                  ej.                  ej0                  ej2                  gej,                  ej2                  gej.                  g ej0                  g ej2                  g iZeeee   f   ed<   ej*                  dej,                  dej.                  dej0                  dej2                  diZ eeef   ed<   defdZ!dedeeef   dede"fdZ#dee   de	e   fdZ$de	e   dee   fd Z%d!eded"ed#ed$ede"fd%Z&	 d7d!eded"ed#ed$ed&e"de
e   fd'Z'	 d8d!edee   d"ed(ee   d$e
e   deeef   fd)Z(d!eded"ed#ed$ed*ed+e
e   d,ee   de
e   fd-Z)d!ed.ed"ed$ed,ee   de"fd/Z*d9d!ed"e
e   d$e
e   defd0Z+d8d!ed"e
e   de"fd1Z,d!ed"ed$efd2Z-d!ed$edeeef   fd3Z.	 d8ded4ed5e
e   fd6Z/y):a  
Task Orchestrator for Smart Inventory
=====================================

This module provides utilities to automatically trigger Celery tasks based on 
affected database tables. It handles:
- Task dependency ordering
- HOLD status for tasks waiting on dependencies
- Polling for HOLD tasks to start when dependencies complete
- Tracking via CeleryTaskTracker

This is a table-based orchestrator - it determines which tasks to run based on
which database tables were modified. It can be used from:
- CSV upload processing (data_import/controller.py)
- Webhook event processing (inventory/webhookcontroller.py)
- Any other data modification flow

Usage:
    from src.smart_inventory.utils.task_orchestrator import trigger_tasks_for_affected_tables
    
    # After any data modification
    trigger_tasks_for_affected_tables(
        db=db,
        affected_tables=["sales_orders", "sales_order_lines", "inventory_movements"],
        company_id=1,
        unique_dates=["2026-01-01", "2026-01-02"]
    )
    N)datetimedate)ListDictSetOptionalAny)Enum)Sessionc                   $    e Zd ZdZdZdZdZdZdZy)TaskNamez*Celery task names for inventory processingcompute_daily_salescompute_inventory_snapshotcompute_service_level_dailycompute_slow_movers_90d#compute_inventory_planning_snapshotN)	__name__
__module____qualname____doc__DAILY_SALESINVENTORY_SNAPSHOTSERVICE_LEVELSLOW_MOVERSINVENTORY_PLANNING     J/var/www/html/hubwallet-dev/src/smart_inventory/utils/task_orchestrator.pyr   r   -   s     4'K51M+K>r   r   TASK_DEPENDENCIES         TASK_PRIORITY)sales_orderssales_order_linessales_return_orderssales_return_order_linesinventory_movementsinventory_movementinventory_batchesinventory_batchpurchase_order_receivepurchase_order_receive_linespurchase_order_returnpurchase_order_return_linesTABLE_TO_TASKSDOWNSTREAM_TASKSz>src.smart_inventory.tasks.daily_sales_task.compute_daily_saleszBsrc.smart_inventory.tasks.snapshot_task.compute_inventory_snapshotzHsrc.smart_inventory.tasks.service_level_task.compute_service_level_dailyzBsrc.smart_inventory.tasks.slow_movers_task.compute_slow_movers_90dzUsrc.smart_inventory.tasks.inventory_planning_task.compute_inventory_planning_snapshotTASK_NAME_TO_CELERY_NAME	task_namec                 x   	 | t         j                  k(  rddlm} |S | t         j                  k(  rddlm} |S | t         j                  k(  rddlm	} |S | t         j                  k(  rddlm} |S | t         j                  k(  rddlm} |S 	 y	# t         $ r%}t"        j%                  d|  d|        Y d	}~y	d	}~ww xY w)
z9Get the actual Celery task function by name (for Windows)r   )r   )r   )r   )r   )r   zCould not import task : N)r   r   *src.smart_inventory.tasks.daily_sales_taskr   r   1src.smart_inventory.tasks.inventory_snapshot_taskr   r   ,src.smart_inventory.tasks.service_level_taskr   r   *src.smart_inventory.tasks.slow_movers_taskr   r   1src.smart_inventory.tasks.inventory_planning_taskr   ImportErrorloggerwarning)r3   r   r   r   r   r   es          r   _get_celery_taskr?      s    ,,,V&&(555d--(000`..(...Z**(555m66 6   /	{"QC@As-   B B B B .B 	B9B44B9kwargstask_idreturnc                 6   	 t         j                  dk(  r"t        |       }|r|j                  ||       yyddlm} t        j                  |       }|r|j                  |||       yy# t        $ r%}t        j                  d|  d|        Y d	}~yd	}~ww xY w)
a  
    Dispatch a Celery task with platform-specific handling.
    
    Windows (solo pool): Uses direct task import and apply_async
    Linux (prefork pool): Uses send_task with task name string
    
    Args:
        task_name: The TaskName enum
        kwargs: Task keyword arguments
        task_id: Task ID to use
        
    Returns:
        True if task was dispatched successfully
    win32)r@   rA   Tr   
celery_appFzFailed to dispatch task r5   N)sysplatformr?   apply_asyncsrc.utils.celery_workerrF   r2   get	send_task	Exceptionr<   error)r3   r@   rA   celery_taskrF   celery_namer>   s          r   _dispatch_celery_taskrQ      s    <<7"*95K''vw'G  ;266yAK$$[$Q /	{"QC@As   3A* 1A* *	B3BBaffected_tablesc                    t               }| D cg c]"  }|j                         j                  dd      $ }}|D ]*  }|t        v st        |   D ]  }|j	                  |        , t        |      }|rU|j                         }t        j                  |g       D ])  }||vs|j	                  |       |j                  |       + |rU|S c c}w )a  
    Determine which tasks need to run based on affected tables.
    Also includes downstream dependent tasks.
    
    Args:
        affected_tables: List of table names that were modified
        
    Returns:
        Set of TaskName enums for tasks that should run
    -_)
setlowerreplacer0   addlistpopr1   rK   append)rR   required_taskstnormalized_tablestabletasktasks_to_checkdownstream_tasks           r   get_required_tasksrd      s     %(EN ?NN**34NN # )N"&u- )""4()) .)N
!!#/33D"= 	7On4""?3%%o6	7  # Os   'Ctasksc                     t        | d       S )z
    Sort tasks by priority/dependency order.
    
    Args:
        tasks: Set of tasks to sort
        
    Returns:
        List of tasks sorted by execution priority
    c                 .    t         j                  | d      S )Nc   )r#   rK   )r^   s    r   <lambda>z$get_tasks_in_order.<locals>.<lambda>   s    }'8'8B'? r   )key)sorted)re   s    r   get_tasks_in_orderrl      s     %?@@r   db
company_idtarget_datebatch_idc                 t   ddl m}m} ddlm} t
        j                  |g       }|sy|j                         j                         }	|t        j                  k(  xr ||	k(  }
|D ]  }|
r|t        j                  k(  rt        j                  j                   d| }| j                  |      j                  |j                  |k(  |j                   j#                  |            j%                         }|D ]M  }|j&                  |j(                  k7  st*        j-                  d|j                    d|j                            y t*        j-                  d	|j                          |j                   d
| d
| }| j                  |      j                  |j                  |k(  |j                   |k(        j/                         }|s(t*        j-                  d|j                   d| d       |j&                  |j(                  k7  st*        j-                  d|j                   d|j                           y y)a  
    Check if all dependencies for a task have completed successfully.
    
    Only checks dependencies that were actually triggered in the current batch.
    If a dependency task doesn't exist in this batch, it's considered "not required"
    and skipped - this handles cases like purchase_receive where DAILY_SALES
    is never triggered but INVENTORY_PLANNING still needs to run.
    
    Special case: INVENTORY_PLANNING for today's date needs to wait for ALL
    DAILY_SALES tasks in the batch (not just today's), because the planning
    calculation uses historical sales data from the past 90 days.
    
    Args:
        db: Database session
        task_name: The task to check dependencies for
        company_id: Company ID
        target_date: Target date string (YYYY-MM-DD)
        batch_id: Batch ID to group related tasks
        
    Returns:
        True if all dependencies are met (SUCCESS status) or not required
    r   CeleryTaskTrackerCeleryTaskStatus)r   T_%_zWaiting for z to complete for Fz#All daily_sales tasks complete for rU   zDependency z not in batch z
, skippingz not yet complete for ))src.smart_inventory.apps.inventory.modelsrs   rt   r   r   r   rK   today	isoformatr   r   r   valuequeryfilterrn   r3   likeallstatusSUCCESSr<   debugfirst)rm   r3   rn   ro   rp   rs   rt   	date_typedependencies	today_stris_planning_for_todaydep_taskpatternall_daily_sales
ds_trackerdep_task_namedep_trackers                    r   check_dependencies_metr      s   : ^*$((B7L
 !++-IX000 	!y  
 ! $ X1E1E%E!--334CzBG hh'89@@!,,
:!++009 ce  . !
$$(8(@(@@LL<
0D0D/EEVW`WfWfVg!hi !
 LL>y>OPQ $>>*!K=(D hh0188((J6''=8
 %' 	 LL;x~~&6nXJjYZ !1!9!99LL;x~~&66LY__L]^_I$L r   check_dependenciesc                 J   ddl m}m} |j                   d| d| }| j	                  |      j                  |j                  |k(  |j                  |k(        j                         }	|	r1t        j                  d| d|	j                          |	j                  S t        t        j                               }
d}|rt!        | ||||      }|r|j"                  n|j$                  } ||
||||rt'        j(                         nd      }| j+                  |       | j-                          |r|t.        j0                  k(  rd	|i}ny|t.        j2                  k(  rd	|i}na|t.        j4                  k(  rd
|i}nI|t.        j6                  k(  rd|i}n1|t.        j8                  k(  rd|i}nt        j;                  d|        y	 t=        |||
      r&t        j                  d|j                   d|        n$t        j;                  d|j                   d       y	 |
S t        j                  |j                   d       |
S # t>        $ r`}t        jA                  d|j                   d|        |jB                  |_        t        |      |_"        | j-                          Y d}~yd}~ww xY w)a}  
    Trigger a single Celery task with tracking.
    
    Args:
        db: Database session
        task_name: Task to trigger
        company_id: Company ID
        target_date: Target date (YYYY-MM-DD)
        batch_id: Batch ID for grouping
        check_dependencies: Whether to check and set HOLD status
        
    Returns:
        Task ID if triggered, None if failed
    r   rr   rU   Task 	 exists: TNrA   r3   rn   r~   
started_atro   target_date_strsnapshot_date_strUnknown task type: z
Triggered  for Celery task  not availableFailed to trigger task r5    set to HOLD)#rv   rs   rt   ry   rz   r{   r3   rn   r   r<   r   r~   rA   struuiduuid4r   PENDINGHOLDr   nowrY   commitr   r   r   r   r   r   r=   rQ   rM   rN   FAILUREerror_message)rm   r3   rn   ro   rp   r   rs   rt   tracker_task_nameexistingrA   dependencies_metinitial_statustrackertask_kwargsr>   s                   r   trigger_single_taskr   E  s   , ^ %??+1[M8*E xx)*11##'88$$
2 eg 
 u./y8IJK $**,G 1"i[Zbc 2B%--GWG\G\N  #%58<<>4G FF7OIIK ,,,(+6K(555(+6K(000,k:K(....<K(555.<KNN0<=	$YWEz)//):%}MNioo->nMN O N 		(56N  	LL29??2C2aSIJ-55GN$'FG!IIK	s   ;AH9 9	J"AJJ"unique_datesc                    ddl m} |s t        t        j                               dd }t        |      }|st        j                  d|        |ddg dS t        j                  t        j                  t        j                  t        j                  t        j                  g}|D cg c]	  }||v s| }	}|}
t        j                         j!                         }|g}t        j#                  d|	D cg c]  }|j$                   c}        t        j#                  d|
 d	t'        |
       d
       t        j#                  d| d       g }d}d}t)        |	      D ]  \  }}|t        j                  k(  r|
}n|}|D ]  }t+        | ||||||dkD  r|	|dz
     nd|
      }|s&ddl m} | j/                  |      j1                  |j2                  |k(        j5                         }|r|j6                  j$                  nd}|j9                  |j$                  ||||dz   d       ||j:                  j$                  k(  r|dz  }|dz  }  |dkD  rt=        | ||       ||||dS c c}w c c}w )a%  
    Main function to trigger all required tasks based on affected tables.
    
    This is the primary entry point for the task orchestrator. Call this after
    CSV processing to automatically trigger all necessary background tasks.
    
    EXECUTION ORDER (wave-based):
    1. DAILY_SALES for ALL unique dates in CSV (computes historical sales data)
    2. INVENTORY_SNAPSHOT for TODAY only (current inventory state)
    3. SERVICE_LEVEL for TODAY only (current service level)
    4. SLOW_MOVERS for TODAY only (current slow mover analysis)
    5. INVENTORY_PLANNING for TODAY only (current planning snapshot)
    
    Each wave waits for the previous wave to complete before starting.
    This ensures proper data availability for dependent calculations.
    
    Args:
        db: Database session
        affected_tables: List of table names that were modified by CSV upload
        company_id: Company ID the data belongs to
        unique_dates: List of unique dates (YYYY-MM-DD) in the uploaded data
        batch_id: Optional batch ID for grouping (auto-generated if not provided)
        
    Returns:
        Dict with triggered task information:
        {
            "batch_id": str,
            "tasks_triggered": int,
            "tasks_on_hold": int,
            "task_details": [...]
        }
    r   )rt   N   zNo tasks for tables: )rp   tasks_triggeredtasks_on_holdtask_detailszWave-based execution: zDAILY_SALES dates:  (z dates)zSnapshot/Planning dates: z (today only)r    )rm   r3   rn   ro   rp   
wave_indexprevious_wave_task	all_dates)rs   unknown)r3   rA   ro   r~   wave)rv   rt   r   r   r   rd   r<   r   r   r   r   r   r   r   r   rw   rx   infory   len	enumeratetrigger_single_task_wavers   rz   r{   rA   r   r~   r\   r   _ensure_hold_poller_running)rm   rR   rn   r   rp   rt   r]   EXECUTION_ORDERr^   ordered_tasksr   r   
today_onlyr   r   r   r   r3   dates_to_processro   rA   rs   r   r~   s                           r   !trigger_tasks_for_affected_tablesr     s   N Ktzz|$Ra( (8N,_,=>?  	
 	
 	####O !0G113FQGMG I

&&(IJ
KK(=)Ia!'')I(JKL
KK%i[3y>2B'JK
KK+J<}EFLOM
 "+=!9 ))
I,,,(  *+  	)K.#%'!%DNQRN=a#@X\#	G W((#45<<%--8%'  29--i##!*&#.$&N%  -22888!Q&M#q(OA 	)))X q#B
H= *&$	 E H *Js   &	I"0I"1I'
r   r   r   c           	      h   ddl m}m}	 |j                   d| d| }
| j	                  |      j                  |j                  |
k(  |j                  |k(        j                         }|r1t        j                  d|
 d|j                          |j                  S t        t        j                               }d}|dkD  r|rt!        | ||||      }|r|	j"                  n|	j$                  } |||
|||rt'        j(                         nd      }| j+                  |       | j-                          |r|t.        j0                  k(  rd	|i}ny|t.        j2                  k(  rd	|i}na|t.        j4                  k(  rd
|i}nI|t.        j6                  k(  rd|i}n1|t.        j8                  k(  rd|i}nt        j;                  d|        y	 t=        |||      r)t        j                  d| d|j                   d|        n$t        j;                  d|j                   d       y	 |S t        j                  d| d|j                   d| d       |S # t>        $ r`}t        jA                  d|j                   d|        |	jB                  |_        t        |      |_"        | j-                          Y d}~yd}~ww xY w)a  
    Trigger a single task with wave-based dependency checking.
    
    Wave 0 tasks run immediately.
    Wave N tasks wait for ALL tasks in wave N-1 to complete.
    
    Args:
        db: Database session
        task_name: Task to trigger
        company_id: Company ID
        target_date: Target date (YYYY-MM-DD)
        batch_id: Batch ID for grouping
        wave_index: Which wave this task belongs to (0-based)
        previous_wave_task: The task type from the previous wave (to wait for)
        all_dates: All dates in this batch (to check all previous wave tasks)
        
    Returns:
        Task ID if triggered, None if failed
    r   rr   rU   r   r   TNr   ro   r   r   r   zWave z: Triggered r   r   r   r   r5   r   )#rv   rs   rt   ry   rz   r{   r3   rn   r   r<   r   r~   rA   r   r   r   check_previous_wave_completer   r   r   r   rY   r   r   r   r   r   r   r   r=   rQ   rM   rN   r   r   )rm   r3   rn   ro   rp   r   r   r   rs   rt   r   r   rA   r   r   r   r   r>   s                     r   r   r   1  s   : ^ %??+1[M8*E xx)*11##'88$$
2 eg 
 u./y8IJK $**,G A~,7"J)

 2B%--GWG\G\N  #%58<<>4G FF7OIIK ,,,(+6K(555(+6K(000,k:K(....<K(555.<KNN0<=	$YWEuZLY__<MUS^R_`aioo->nMN b N 	uZL9??*;5\Z[N  	LL29??2C2aSIJ-55GN$'FG!IIK	s    AI 	J1AJ,,J1previous_taskc                    ddl m}m} |D ]  }|j                   d| d| }| j	                  |      j                  |j                  |k(  |j                  |k(        j                         }	|	st        j                  d|         y|	j                  |j                  k7  st        j                  d| d|	j                  j                   d        y t        j                  d	|j                   d
t        |       d       y)az  
    Check if ALL tasks of the previous wave (for all dates) have completed.
    
    Args:
        db: Database session
        previous_task: The task type from the previous wave
        company_id: Company ID
        batch_id: Batch ID
        all_dates: All dates in this batch
        
    Returns:
        True if all previous wave tasks are complete (SUCCESS status)
    r   rr   rU   zPrevious wave task not found: Fz!Previous wave task not complete: r   )zPrevious wave (z) complete for all z datesT)rv   rs   rt   ry   rz   r{   r3   rn   r   r<   r   r~   r   r   )
rm   r   rn   rp   r   rs   rt   ro   r3   r   s
             r   r   r     s    ( ^  $**+1[M8*E	((,-44''94((J6
 %' 	 LL9)EF>>-555LL<YKr'..J^J^I__`ab" LL?=#6#6"77J3y>JZZ`abr   c                 B   ddl m}m} t        j                  t        j
                  t        j                  t        j                  t        j                  g}| j                  |      j                  |j                  |j                  k(        }|r|j                  |j                  |k(        }|j                         }|syd}|D ]j  }	|	j                  j!                  dd      }
t#        |
      dk  r/|
d   }|
d   }|
d   }|r||k7  rFd}d}t%        |      D ]  \  }}|j&                  |k(  s|}|} n |r|dk  rz|dk(  rd	}n||dz
     }|j&                   d
| }| j                  |      j                  |j                  |	j                  k(  |j                  j)                  |            j                         }d	}|sd	}n$|D ]  }|j                  |j*                  k7  sd} n |s)|t        j                  k(  rd|i}nb|t        j
                  k(  rd|i}nJ|t        j                  k(  rd|i}n2|t        j                  k(  rd|i}n|t        j                  k(  rd|i}n	 |j,                  |	_        t/        j0                         |	_        | j5                          t7        |||	j8                        r,t:        j=                  d|	j                   d| d       |dz  }nJt:        j?                  d|	j                          |j@                  |	_        d|	_!        | j5                          m |S # tD        $ ra}t:        j?                  d|	j                   d|        |j@                  |	_        tG        |      |	_!        | j5                          Y d}~d}~ww xY w)a\  
    Check HOLD tasks and start them if previous wave is complete.
    
    Wave-based approach: tasks wait for ALL tasks of the previous wave to complete.
    
    Args:
        db: Database session
        company_id: Optional filter by company
        batch_id: Optional filter by batch
        
    Returns:
        Number of tasks started
    r   rr   rU   r!   r"   r    NTru   Fro   r   r   zStarted HOLD task: z (wave r   zFailed to dispatch HOLD task zFailed to dispatch taskzFailed to start HOLD task r5   )$rv   rs   rt   r   r   r   r   r   r   rz   r{   r~   r   rn   r}   r3   rsplitr   r   ry   r|   r   r   r   r   r   r   rQ   rA   r<   r   rN   r   r   rM   r   )rm   rn   rp   rs   rt   r   rz   
hold_taskstasks_startedr   parts
task_valuero   task_batch_idr3   r   itnr   r   r   previous_wave_tasksprev_trackerr   r>   s                            r   process_hold_tasksr     s    ^ 	####O HH&'..  $4$9$99E .99ZGHJM U !!((a0u:>1X
Aha1 	
/ 	EArxx:%	
		 JN ?# ,JN;M&,,-S@G"$((+<"="D"D!,,0B0BB!++009# ce    $&#' $7 L#**.>.F.FF+0(
 H000,k:h999,k:h4440+>h2222K@h9992K@!1!9!9%-\\^"		 )KQLL#6w7H7H6IQ[P\\]!^_!Q&MLL#@ARAR@S!TU%5%=%=GN,EG)IIK_Un   9':K:K9LBqcRS!1!9!9(+A%			s   (CL44	N=ANNc                     ddl m}m} | j                  |      j	                  |j
                  |j                  k(        }|r|j	                  |j                  |k(        }|j                         duS )z+Check if there are any tasks in HOLD statusr   rr   N)	rv   rs   rt   rz   r{   r~   r   rn   r   )rm   rn   rs   rt   rz   s        r   has_hold_tasksr   J  sd    ]HH&'..  $4$9$99E .99ZGH;;=$$r   c                 $   	 t         j                  dk(  rddlm} |j	                  ||       nddlm} |j                  d||d       t        j                  d|        y
# t        $ r"}t        j                  d	|        Y d
}~y
d
}~ww xY w)zu
    Ensure the background poller for HOLD tasks is running.
    Uses a Celery task that polls every 20 seconds.
    rD   r   )poll_hold_tasks)rn   rp   rE   z:src.smart_inventory.tasks.hold_task_poller.poll_hold_tasks)r@   zStarted hold poller for batch z"Failed to start hold task poller: N)rG   rH   *src.smart_inventory.tasks.hold_task_pollerr   delayrJ   rF   rL   r<   r   rM   r=   )rm   rn   rp   r   rF   r>   s         r   r   r   X  s    
A<<7"R!!Z(!K ;  L&0hG !  	4XJ?@ A;A3?@@As   A!A$ $	B-B

Bc           
         ddl m}m} | j                  |      j	                  |j
                  j                  d|             j                         }dddddt        |      d}g }|D ]  }|j                  |j                  j                  d      dz   ||j                  j                  <   |j                  |j                  |j
                  |j                  j                  |j                  r|j                  j                         nd|j                   r|j                   j                         nd|j"                  d        |d   |d	   z   |d
   k(  }||||dS )z
    Get the status of all tasks in a batch.
    
    Args:
        db: Database session
        batch_id: Batch ID to check
        
    Returns:
        Dict with batch status information
    r   rr   z%_)pendingstartedsuccessfailureholdtotalr    N)rA   r3   r~   r   completed_atr   r   r   r   )rp   status_countsall_completere   )rv   rs   rt   rz   r{   r3   r|   r}   r   rK   r~   ry   r\   rA   r   rx   r   r   )	rm   rp   rs   rt   re   r   	task_listra   r   s	            r   get_batch_statusr   r  sR    ^HH&'..##((2hZ9	ce 

 UM I 	+8+<+<T[[=N=NPQ+RUV+Vdkk''(||kk''9=$//335d=A=N=ND--779TX!//
 		 !+mI.FF-X_J``L &$	 r   r~   r   c                    	 ddl m} ddlm}m}  |       }	 |j                  |      j                  |j                  | k(        j                         }|r|j                  |j                  |j                  |j                  |j                  d}|j                  |j                               }	|	rF|	|_        |j                         dk(  rt#        j$                         |_        n+|j                         dv rt#        j$                         |_        |r
|dd |_        |j-                          t.        j1                  d	|  d
|        |j                         dk(  r|j2                  r|j4                  r|j4                  j7                  dd      ng }
t9        |
      dk\  r|
d   nd}	 t;        ||j2                  |      }|dkD  rt.        j=                  d| d|  d       nt.        jA                  d|         |jC                          y# t>        $ r"}t.        jA                  d|        Y d}~7d}~ww xY w# |jC                          w xY w# t>        $ r"}t.        jE                  d|        Y d}~yd}~ww xY w)a  
    Update CeleryTaskTracker status for a task.
    Call this from within Celery tasks to update their tracking status.
    
    When status is 'success', automatically triggers processing of HOLD tasks
    that may have been waiting for this task to complete.
    
    Args:
        task_id: The Celery task ID
        status: New status (started, success, failure)
        error_message: Optional error message for failure status
    r   )get_db_sessionrr   )r   r   r   r   retryr   )r   r   Ni  zUpdated task z status to r   rU   r!   r"   zAuto-started z HOLD tasks after z
 completedzFailed to process hold tasks: zNo tracker found for task_id z&Failed to update task tracker status: )#src.utils.dbr   rv   rs   rt   rz   r{   rA   r   STARTEDr   r   r   RETRYrK   rW   r~   r   r   r   r   r   r   r<   r   rn   r3   r   r   r   r   rM   r=   closerN   )rA   r~   r   r   rs   rt   rm   r   
status_map
new_statusr   rp   r   hold_errr>   s                  r   update_task_tracker_statusr     s%   "4C/a-	hh0188!))W4eg    077/77/77/77-33
 (^^FLLN;
%/GN||~2-5\\^*+AA/7||~,$0=et0D-IIKLL=	VH!MN ||~2w7I7IDKDUDU 1 1 8 8a @[]/25zQ58DX&8W=O=OQY&ZG&{ &mG9DVW^V__i,j k !>wiHIHHJ  ) X"NN-KH:+VWWX
 HHJ C=aSABBCsY   I FH7 '8H	 H7 8I 		H4H/*H7 /H44H7 7I		I 	I7I22I7)T)N)NN)0r   loggingrG   r   r   r   typingr   r   r   r   r	   enumr
   sqlalchemy.ormr   	getLoggerr   r<   r   r   r   r   r   r   r   r   __annotations__r#   intr0   r1   r2   r?   boolrQ   rd   rl   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>r      sv  :  
  # 1 1  "			8	$?sD ? "X1128//0("="=x?S?S!T5 4$x.01  !A!&tHcM"  ))*"../$001!)!5!5 6 %778#667 #556 334  (::;%-%@%@$A '99:$,$?$?#@--S$x.() 8 81183G3GIdIde("="=!>B"4 $xh/0  Z!ef^!x1 $x}-  0 X  tCH~  PS  X\  NS	 c(m D
Ac(m 
AX 
ATTT T 	T
 T 
Tz  $\\\ \ 	\
 \ \ c]\H #JJ#YJ J s)	J
 smJ 
#s(^JZeee e 	e
 e e !*e Cye c]eP((( ( 	(
 Cy( 
(^7  PXY\P] il D%w %HSM %T %AG A A A4- -C -DcN -n $(ECECEC C=ECr   