1919from typing import Optional
2020import subprocess
2121import requests
22+ import traceback
23+ import pathlib
2224
2325# Local
2426import process
2830from process import PROCESSING_SPEED
2931
3032CALLBACK_SERVER : str = os .getenv ("CALLBACK_SERVER" ) or ""
33+ NUM_WORKERS = int (os .getenv ("NUM_WORKERS" ) or 1 )
3134
3235
3336def run_pending_tasks () -> None :
@@ -38,7 +41,8 @@ def run_pending_tasks() -> None:
3841 global pool
3942
4043 # One task at a time.
41- if StatusLogger .busy_task_exists ():
44+ tasks_in_queue = pool ._taskqueue .qsize ()
45+ if tasks_in_queue > 0 :
4246 return
4347
4448 # Start new task when not busy
@@ -52,11 +56,9 @@ def run_pending_tasks() -> None:
5256 # Extra None check for typing
5357 if (not is_pool_running (pool )) or pool is None :
5458 # Spawn pool if not running
55- pool = mp .Pool (processes = 1 , initializer = process .init )
59+ pool = mp .Pool (processes = NUM_WORKERS , initializer = process .init )
5660 # Perform task at running pool
5761 pool .apply_async (process_file , args = (sl .filename ,))
58- # Only start one task at a time, so return.
59- return
6062
6163
6264def process_file (filename : str ):
@@ -83,9 +85,9 @@ def process_file(filename: str):
8385 # Process failed, free up the pid
8486 ps .delete_status ()
8587 sl .error (f"An exception occurred: { e } " )
88+ print (traceback .format_exc ())
8689 # copy input file to error folder if it exists
87- if os .path .exists (in_path ):
88- sl .error ("Moving input file to error folder" )
90+ if os .path .isfile (in_path ):
8991 os .rename (in_path , error_path )
9092 if CALLBACK_SERVER != "" :
9193 sl .error ("Sending error to callback server" )
@@ -97,20 +99,32 @@ def tag(
9799) -> None :
98100 """
99101 Attempt to tag the file by the tagger with a timeout.
100- Send the result to the server, whether sucessful or not.
101- Also appropiately logs the status.
102+ Send the result to the server, whether successful or not.
103+ Also appropriately logs the status.
102104 """
103105 # 300s = 5min fixed time
104106 # plus
105107 # bytes * speed variable time
106- in_bytes_size = int (
107- subprocess .check_output (["du" , "-sb" , in_path ]).split ()[0 ].decode ("utf-8" )
108- )
109- TIMEOUT = 300 + in_bytes_size + PROCESSING_SPEED
110- sl .busy ("Will process with a timeout after " + str (TIMEOUT ) + " seconds" )
111-
112- # Runs the respective tagger software.
113- @timeout (TIMEOUT , os .strerror (errno .ETIME ))
108+ in_bytes_size = None
109+ while in_bytes_size is None :
110+ if os .path .isfile (in_path ):
111+ try :
112+ in_bytes_size = int (
113+ subprocess .check_output (["du" , "-sb" , in_path ])
114+ .split ()[0 ]
115+ .decode ("utf-8" )
116+ )
117+ except Exception as e :
118+ print (f"Error getting file size: { e } " )
119+ time .sleep (1 )
120+ else :
121+ raise FileNotFoundError (f"File { in_path } not found" )
122+
123+ time_out = 300 + in_bytes_size + PROCESSING_SPEED
124+ sl .busy ("Will process with a timeout after " + str (time_out ) + " seconds" )
125+
126+ # Runs the respective tagger software synchronously.
127+ @timeout (time_out , os .strerror (errno .ETIME ))
114128 def doTagging ():
115129 process .process (in_path , out_path )
116130
@@ -119,11 +133,7 @@ def doTagging():
119133 # Done processing
120134 ps .delete_status () # Frees up the tagger
121135 sl .finished ("Removing input file" )
122- # "try", because the task might have been cancelled and deleted in the meantime.
123- try :
124- os .remove (in_path )
125- except :
126- pass
136+ pathlib .Path (in_path ).unlink (missing_ok = True )
127137
128138 sl .finished (
129139 "Finished processing %s, result has size %d"
@@ -167,8 +177,9 @@ def send_error_to_callback_server(filename: str, out_path: str, message: str) ->
167177 Send the error to the callback server and keep or delete the file based on the server response.
168178 """
169179 url = CALLBACK_SERVER + "/error"
170- payload = {"file_id" : filename , "message" : message }
171- r = requests .post (url , data = payload )
180+ payload = {"file_id" : filename }
181+ json_data = {"file_id" : filename , "message" : message }
182+ r = requests .post (url , json = json_data , params = payload )
172183 keep_or_delete_file (r , out_path )
173184
174185
@@ -188,12 +199,15 @@ def is_pool_running(pool: Optional[Pool]) -> bool:
188199
189200# Pool needs to be defined after the functions it will execute.
190201# https://stackoverflow.com/questions/41385708/multiprocessing-example-giving-attributeerror#comment101561695_42383397
191- pool : Optional [Pool ] = mp .Pool (processes = 1 , initializer = process .init )
192-
202+ pool = None
193203
194- # It is ugly, but it is also used here:
195- # https://pypi.org/project/schedule/
196204if __name__ == "__main__" :
205+ # Can't use fork with the gpu.
206+ mp .set_start_method ("spawn" , force = True )
207+ pool = mp .Pool (processes = NUM_WORKERS , initializer = process .init )
208+
209+ # It is ugly, but it is also used here:
210+ # https://pypi.org/project/schedule/
197211 while True :
198212 run_pending_tasks ()
199- time .sleep (1 )
213+ time .sleep (1 )
0 commit comments