diff --git a/lib/job_server.py b/lib/job_server.py index d1ad9bb..1ae3b63 100755 --- a/lib/job_server.py +++ b/lib/job_server.py @@ -22,13 +22,13 @@ server = Flask(__name__) @server.get('/jobs') def jobs_json(): - return [json.loads(x.json()) for x in RenderQueue.job_queue if not x.archived] + return [x.json_safe_copy() for x in RenderQueue.job_queue if not x.archived] @server.get('/jobs/') def filtered_jobs_json(status_val): state = string_to_status(status_val) - jobs = [json.loads(x.json()) for x in RenderQueue.jobs_with_status(state)] + jobs = [x.json_safe_copy() for x in RenderQueue.jobs_with_status(state)] if jobs: return jobs else: @@ -39,7 +39,7 @@ def filtered_jobs_json(status_val): def get_job_status(job_id): found_job = RenderQueue.job_with_id(job_id) if found_job: - return found_job.json() + return found_job.json_safe_copy() else: return f'Cannot find job with ID {job_id}', 400 @@ -130,17 +130,13 @@ def full_status(): @server.get('/snapshot') def snapshot(): server_status = RenderQueue.status() - server_jobs = [json.loads(x.json()) for x in RenderQueue.job_queue if not x.archived] + server_jobs = [x.json_safe_copy() for x in RenderQueue.job_queue if not x.archived] server_data = {'status': server_status, 'jobs': server_jobs, 'timestamp': datetime.now().isoformat()} return server_data @server.post('/add_job') -def add_job(): - def remove_job_dir(): - if job_dir and os.path.exists(job_dir): - logger.debug(f"Removing job dir: {job_dir}") - shutil.rmtree(job_dir) +def add_job_handler(): try: """Create new job and add to server render queue""" @@ -148,25 +144,7 @@ def add_job(): if not json_string: return 'missing json data', 400 - request_params = json.loads(json_string) - job_owner = request_params.get("owner", None) - renderer = request_params.get("renderer", None) - input_path = request_params.get("input", None) - output_path = request_params.get("output", None) - priority = int(request_params.get('priority', 2)) - args = request_params.get('args', {}) - client = request_params.get('client', RenderQueue.host_name) - force_start = request_params.get('force_start', False) - uploaded_file = request.files.get('file', None) - html_origin = request_params.get('origin', None) == 'html' - custom_id = None - job_dir = None - - # check for minimum render requirements - if None in [renderer, input_path or (uploaded_file and uploaded_file.filename), output_path]: - err_msg = 'Cannot add job: Missing required parameters' - logger.error(err_msg) - return err_msg, 400 + print(json_string) # handle uploaded files if uploaded_file and uploaded_file.filename: diff --git a/lib/render_job.py b/lib/render_job.py index 1e86239..e4dda12 100644 --- a/lib/render_job.py +++ b/lib/render_job.py @@ -41,37 +41,48 @@ class RenderJob: def file_hash(self): return hashlib.md5(open(self.worker.input_path, 'rb').read()).hexdigest() - def json(self): - """Converts RenderJob into JSON format""" + def json_safe_copy(self): + """Converts RenderJob into JSON-friendly dict""" import numbers - - def date_serializer(o): - if isinstance(o, datetime): - return o.isoformat() - - json_string = '' - + job_dict = None try: - d = self.__dict__.copy() - d['status'] = self.render_status().value - d['file_hash'] = self.file_hash if isinstance(self.file_hash, str) else self.file_hash() - d['worker'] = self.worker.__dict__.copy() - for key in ['thread', 'process']: # remove unwanted keys from JSON - d['worker'].pop(key, None) - d['worker']['status'] = d['status'] + job_dict = self.__dict__.copy() + job_dict['status'] = self.render_status().value + job_dict['file_hash'] = self.file_hash if isinstance(self.file_hash, str) else self.file_hash() + job_dict['worker'] = self.worker.__dict__.copy() + job_dict['worker']['status'] = job_dict['status'] + + # remove unwanted keys from dict + keys_to_remove = ['thread', 'process'] + for key in job_dict['worker'].keys(): + if key.startswith('_'): + keys_to_remove.append(key) + for key in keys_to_remove: + job_dict['worker'].pop(key, None) # jobs from current_session generate percent completed # jobs after loading server pull in a saved value. Have to check if callable object or not percent_complete = self.worker.percent_complete if isinstance(self.worker.percent_complete, numbers.Number) \ else self.worker.percent_complete() - d['worker']['percent_complete'] = percent_complete + job_dict['worker']['percent_complete'] = percent_complete - json_string = json.dumps(d, default=date_serializer) + # convert to json and back to auto-convert dates to iso format + def date_serializer(o): + if isinstance(o, datetime): + return o.isoformat() + json_convert = json.dumps(job_dict, default=date_serializer) + job_dict = json.loads(json_convert) except Exception as e: logger.exception(e) logger.error("Error converting to JSON: {}".format(e)) - return json_string + return job_dict + + def start(self): + self.worker.start() + + def stop(self): + self.worker.stop() @classmethod def generate_id(cls): diff --git a/lib/render_queue.py b/lib/render_queue.py index 10f696d..97f0cff 100755 --- a/lib/render_queue.py +++ b/lib/render_queue.py @@ -165,16 +165,13 @@ class RenderQueue: def start_job(cls, job): logger.info('Starting {}render: {} - Priority {}'.format('scheduled ' if job.scheduled_start else '', job.name, job.priority)) - job.worker.start() + job.start() @classmethod def cancel_job(cls, job): logger.info('Cancelling job ID: {}'.format(job.id)) - if job.render_status() in [RenderStatus.NOT_STARTED, RenderStatus.RUNNING, RenderStatus.ERROR]: - job.worker.stop() - job.worker.status = RenderStatus.CANCELLED - return True - return False + job.stop() + return job.render_status == RenderStatus.CANCELLED @classmethod def renderer_instances(cls):