44import shutil
55import subprocess
66import tempfile
7+ import time
78import uuid
89
910from dataclasses import dataclass
1314
1415logger = get_logger (__name__ )
1516
17+ # Default timeout for cwl-demangle subprocess (in seconds)
18+ DEFAULT_DEMANGLE_TIMEOUT = int (os .environ .get ("LAUNCHPAD_DEMANGLE_TIMEOUT" , "10" ))
19+
20+ # Default chunk size for batching symbols
21+ DEFAULT_CHUNK_SIZE = int (os .environ .get ("LAUNCHPAD_DEMANGLE_CHUNK_SIZE" , "500" ))
22+
1623
1724@dataclass
1825class CwlDemangleResult :
@@ -75,7 +82,7 @@ def demangle_all(self) -> Dict[str, CwlDemangleResult]:
7582 self .queue .clear ()
7683
7784 # Process in chunks to avoid potential issues with large inputs
78- chunk_size = 5000
85+ chunk_size = DEFAULT_CHUNK_SIZE
7986 total_chunks = (len (names ) + chunk_size - 1 ) // chunk_size
8087
8188 chunks : List [Tuple [List [str ], int ]] = []
@@ -84,7 +91,7 @@ def demangle_all(self) -> Dict[str, CwlDemangleResult]:
8491 chunk_idx = i // chunk_size
8592 chunks .append ((chunk , chunk_idx ))
8693
87- # Only use parallel processing if workload justifies multiprocessing overhead (≥4 chunks = ≥20K symbols )
94+ # Only use parallel processing if workload justifies multiprocessing overhead (≥4 chunks)
8895 do_in_parallel = self .use_parallel and total_chunks >= 4
8996
9097 logger .debug (
@@ -149,6 +156,8 @@ def _demangle_chunk_worker(
149156 if not chunk :
150157 return {}
151158
159+ start_time = time .time ()
160+
152161 binary_path = shutil .which ("cwl-demangle" )
153162 if binary_path is None :
154163 logger .error ("cwl-demangle binary not found in PATH" )
@@ -178,9 +187,16 @@ def _demangle_chunk_worker(
178187 command_parts .append ("--continue-on-error" )
179188
180189 try :
181- result = subprocess .run (command_parts , capture_output = True , text = True , check = True )
190+ result = subprocess .run (
191+ command_parts , capture_output = True , text = True , check = True , timeout = DEFAULT_DEMANGLE_TIMEOUT
192+ )
193+ except subprocess .TimeoutExpired :
194+ elapsed = time .time () - start_time
195+ logger .exception ("cwl-demangle subprocess timed out" , extra = {"chunk_idx" : chunk_idx , "elapsed" : elapsed })
196+ return {}
182197 except subprocess .CalledProcessError :
183- logger .exception (f"cwl-demangle failed for chunk { chunk_idx } " )
198+ elapsed = time .time () - start_time
199+ logger .exception ("cwl-demangle subprocess failed" , extra = {"chunk_idx" : chunk_idx , "elapsed" : elapsed })
184200 return {}
185201
186202 batch_result = json .loads (result .stdout )
0 commit comments