91
91
AnyProcessRef ,
92
92
AnyResponseType ,
93
93
AnyServiceRef ,
94
+ AnySettingsContainer ,
94
95
AnyViewResponse ,
95
96
AnyValueType ,
96
97
CeleryResult ,
@@ -754,7 +755,7 @@ def submit_job(request, reference, tags=None, process_id=None):
754
755
755
756
def submit_job_handler (payload , # type: ProcessExecution
756
757
settings , # type: SettingsType
757
- service_url , # type: str
758
+ wps_url , # type: str
758
759
provider = None , # type: Optional[AnyServiceRef]
759
760
process = None , # type: AnyProcessRef
760
761
is_workflow = False , # type: bool
@@ -767,9 +768,11 @@ def submit_job_handler(payload, # type: ProcessExecution
767
768
context = None , # type: Optional[str]
768
769
): # type: (...) -> AnyResponseType
769
770
"""
770
- Submits the job to the Celery worker with provided parameters .
771
+ Parses parameters that defines the submitted :term:`Job`, and responds accordingly with the selected execution mode .
771
772
772
- Assumes that parameters have been pre-fetched and validated, except for the :paramref:`payload`.
773
+ Assumes that parameters have been pre-fetched and validated, except for the :paramref:`payload` containing the
774
+ desired inputs and outputs from the :term:`Job`. The selected execution mode looks up the various combinations
775
+ of headers and body parameters available across :term:`API` implementations and revisions.
773
776
"""
774
777
json_body = validate_job_schema (payload )
775
778
db = get_db (settings )
@@ -820,58 +823,93 @@ def submit_job_handler(payload, # type: ProcessExecution
820
823
store = db .get_store (StoreJobs ) # type: StoreJobs
821
824
job = store .save_job (task_id = job_status , process = process , service = provider_id ,
822
825
inputs = job_inputs , outputs = job_outputs , is_workflow = is_workflow , is_local = is_local ,
823
- execute_async = is_execute_async , execute_response = exec_resp , execute_return = exec_return ,
826
+ execute_async = is_execute_async , execute_wait = wait ,
827
+ execute_response = exec_resp , execute_return = exec_return ,
824
828
custom_tags = tags , user_id = user , access = visibility , context = context , subscribers = subscribers ,
825
829
accept_type = accept_type , accept_language = language )
826
830
job .save_log (logger = LOGGER , message = job_message , status = job_status , progress = 0 )
827
-
831
+ job . wps_url = wps_url
828
832
job = store .update_job (job )
829
- location_url = job .status_url (settings )
833
+
834
+ return submit_job_dispatch_task (job , headers = req_headers , container = settings )
835
+
836
+
837
+ def submit_job_dispatch_task (
838
+ job , # type: Job
839
+ * , # force named keyword arguments after
840
+ container , # type: AnySettingsContainer
841
+ headers = None , # type: AnyHeadersContainer
842
+ ): # type: (...) -> AnyResponseType
843
+ """
844
+ Submits the :term:`Job` to the :mod:`celery` worker with provided parameters.
845
+
846
+ Assumes that parameters have been pre-fetched, validated, and can be resolved from the :term:`Job`.
847
+ """
848
+ db = get_db (container )
849
+ store = db .get_store (StoreJobs )
850
+
851
+ location_url = job .status_url (container )
830
852
resp_headers = {"Location" : location_url }
831
- resp_headers . update ( applied )
853
+ req_headers = copy . deepcopy ( headers or {} )
832
854
833
855
task_result = None # type: Optional[CeleryResult]
856
+ job_pending_created = job .status == Status .CREATED
834
857
if not job_pending_created :
835
- wps_url = clean_ows_url (service_url )
858
+ wps_url = clean_ows_url (job . wps_url )
836
859
task_result = execute_process .delay (job_id = job .id , wps_url = wps_url , headers = headers )
837
860
LOGGER .debug ("Celery pending task [%s] for job [%s]." , task_result .id , job .id )
838
- if not job_pending_created and not is_execute_async :
839
- LOGGER .debug ("Celery task requested as sync if it completes before (wait=%ss)" , wait )
861
+
862
+ execute_sync = not job_pending_created and not job .execute_async
863
+ if execute_sync :
864
+ LOGGER .debug ("Celery task requested as sync if it completes before (wait=%ss)" , job .execution_wait )
840
865
try :
841
- task_result .wait (timeout = wait )
866
+ task_result .wait (timeout = job . execution_wait )
842
867
except CeleryTaskTimeoutError :
843
868
pass
844
869
if task_result .ready ():
845
870
job = store .fetch_by_id (job .id )
846
871
# when sync is successful, it must return the results direct instead of status info
847
872
# see: https://docs.ogc.org/is/18-062r2/18-062r2.html#sc_execute_response
848
873
if job .status == Status .SUCCEEDED :
874
+ _ , _ , sync_applied = parse_prefer_header_execute_mode (req_headers , [ExecuteControlOption .SYNC ])
875
+ if sync_applied :
876
+ resp_headers .update (sync_applied )
849
877
return get_job_results_response (
850
878
job ,
851
879
request_headers = req_headers ,
852
880
response_headers = resp_headers ,
853
- container = settings ,
881
+ container = container ,
854
882
)
855
883
# otherwise return the error status
856
- body = job .json (container = settings )
884
+ body = job .json (container = container )
857
885
body ["location" ] = location_url
858
886
resp = get_job_submission_response (body , resp_headers , error = True )
859
887
return resp
860
888
else :
861
- LOGGER .debug ("Celery task requested as sync took too long to complete (wait=%ss). Continue in async." , wait )
862
- # sync not respected, therefore must drop it
863
- # since both could be provided as alternative preferences, drop only async with limited subset
864
- prefer = get_header ("Preference-Applied" , headers , pop = True )
865
- _ , _ , async_applied = parse_prefer_header_execute_mode ({"Prefer" : prefer }, [ExecuteControlOption .ASYNC ])
866
- if async_applied :
867
- resp_headers .update (async_applied )
889
+ job .save_log (
890
+ logger = LOGGER ,
891
+ level = logging .WARNING ,
892
+ message = (
893
+ f"Job requested as synchronous execution took too long to complete (wait={ job .execution_wait } s). "
894
+ "Will resume with asynchronous execution."
895
+ )
896
+ )
897
+ job = store .update_job (job )
898
+ execute_sync = False
899
+
900
+ if not execute_sync :
901
+ # either sync was not respected, therefore must drop it, or it was not requested at all
902
+ # since both could be provided as alternative preferences, drop only sync with limited subset
903
+ _ , _ , async_applied = parse_prefer_header_execute_mode (req_headers , [ExecuteControlOption .ASYNC ])
904
+ if async_applied :
905
+ resp_headers .update (async_applied )
868
906
869
907
LOGGER .debug ("Celery task submitted to run async." )
870
908
body = {
871
909
"jobID" : job .id ,
872
910
"processID" : job .process ,
873
- "providerID" : provider_id , # dropped by validator if not applicable
874
- "status" : map_status (job_status ),
911
+ "providerID" : job . service , # dropped by validator if not applicable
912
+ "status" : map_status (job . status ),
875
913
"location" : location_url , # for convenience/backward compatibility, but official is Location *header*
876
914
}
877
915
resp_headers = update_preference_applied_return_header (job , req_headers , resp_headers )
@@ -893,7 +931,7 @@ def update_job_parameters(job, request):
893
931
def validate_job_json (request ):
894
932
# type: (Request) -> JSON
895
933
"""
896
- Validates that the request contains valid :term:`JSON` conctens , but not ncessary valid against expected schema.
934
+ Validates that the request contains valid :term:`JSON` contents , but not necessary valid against expected schema.
897
935
898
936
.. seealso::
899
937
:func:`validate_job_schema`
0 commit comments