14
14
from itertools import chain
15
15
from collections import defaultdict
16
16
from json import dumps , loads
17
+ from time import sleep
17
18
18
19
from future .utils import viewitems , viewvalues
19
20
import networkx as nx
@@ -420,21 +421,59 @@ def release_validators(self):
420
421
"Only artifact transformation and private jobs can "
421
422
"release validators" )
422
423
423
- # Check if all the validators are ready by checking that there is
424
- # no validator processing job whose status is not waiting
424
+ # Check if all the validators are completed. Validator jobs can be
425
+ # in two states when completed: 'waiting' in case of success
426
+ # or 'error' otherwise
425
427
sql = """SELECT COUNT(1)
426
428
FROM qiita.processing_job_validator pjv
427
429
JOIN qiita.processing_job pj ON
428
430
pjv.validator_id = pj.processing_job_id
429
431
JOIN qiita.processing_job_status USING
430
432
(processing_job_status_id)
431
433
WHERE pjv.processing_job_id = %s
432
- AND processing_job_status != %s"""
433
- qdb .sql_connection .TRN .add (sql , [self .id , 'waiting' ])
434
+ AND processing_job_status NOT IN %s"""
435
+ sql_args = [self .id , ('waiting' , 'error' )]
436
+ qdb .sql_connection .TRN .add (sql , sql_args )
434
437
remaining = qdb .sql_connection .TRN .execute_fetchlast ()
435
438
436
- if remaining == 0 :
437
- # All validators have completed
439
+ # Active polling - wait until all validator jobs are completed
440
+ while remaining != 0 :
441
+ self .step = "Validating outputs (%d remaining)" % remaining
442
+ sleep (10 )
443
+ qdb .sql_connection .TRN .add (sql , sql_args )
444
+ remaining = qdb .sql_connection .TRN .execute_fetchlast ()
445
+
446
+ # Check if any of the validators errored
447
+ sql = """SELECT validator_id
448
+ FROM qiita.processing_job_validator pjv
449
+ JOIN qiita.processing_job pj
450
+ ON pjv.validator_id = pj.processing_job_id
451
+ JOIN qiita.processing_job_status USING
452
+ (processing_job_status_id)
453
+ WHERE pjv.processing_job_id = %s AND
454
+ processing_job_status = %s"""
455
+ qdb .sql_connection .TRN .add (sql , [self .id , 'error' ])
456
+ errored = qdb .sql_connection .TRN .execute_fetchflatten ()
457
+
458
+ if errored :
459
+ # At least one of the validators failed, Set the rest of the
460
+ # validators and the current job as failed
461
+ qdb .sql_connection .TRN .add (sql , [self .id , 'waiting' ])
462
+ waiting = qdb .sql_connection .TRN .execute_fetchflatten ()
463
+
464
+ common_error = "\n " .join (
465
+ ["Validator %s error message: %s"
466
+ % (j , ProcessingJob (j ).log .msg ) for j in errored ])
467
+
468
+ val_error = "%d sister validator jobs failed: %s" % (
469
+ len (errored ), common_error )
470
+ for j in waiting :
471
+ ProcessingJob (j )._set_error (val_error )
472
+
473
+ self ._set_error ('%d validator jobs failed: %s'
474
+ % (len (errored ), common_error ))
475
+ else :
476
+ # All validators have successfully completed
438
477
sql = """SELECT validator_id
439
478
FROM qiita.processing_job_validator
440
479
WHERE processing_job_id = %s"""
@@ -460,8 +499,6 @@ def release_validators(self):
460
499
461
500
self ._update_and_launch_children (mapping )
462
501
self ._set_status ('success' )
463
- else :
464
- self .step = "Validating outputs (%d remaining)" % remaining
465
502
466
503
def _complete_artifact_definition (self , artifact_data ):
467
504
""""Performs the needed steps to complete an artifact definition job
@@ -487,7 +524,6 @@ def _complete_artifact_definition(self, artifact_data):
487
524
if job_params ['provenance' ] is not None :
488
525
# The artifact is a result from a previous job
489
526
provenance = loads (job_params ['provenance' ])
490
- job = ProcessingJob (provenance ['job' ])
491
527
if provenance .get ('data_type' ) is not None :
492
528
artifact_data = {'data_type' : provenance ['data_type' ],
493
529
'artifact_data' : artifact_data }
@@ -500,7 +536,6 @@ def _complete_artifact_definition(self, artifact_data):
500
536
qdb .sql_connection .TRN .execute ()
501
537
# Can't create the artifact until all validators are completed
502
538
self ._set_status ('waiting' )
503
- job .release_validators ()
504
539
else :
505
540
# The artifact is uploaded by the user or is the initial
506
541
# artifact of an analysis
@@ -619,6 +654,16 @@ def _complete_artifact_transformation(self, artifacts_data):
619
654
for j in validator_jobs :
620
655
j .submit ()
621
656
657
+ # Submit the job that will release all the validators
658
+ plugin = qdb .software .Software .from_name_and_version (
659
+ 'Qiita' , 'alpha' )
660
+ cmd = plugin .get_command ('release_validators' )
661
+ params = qdb .software .Parameters .load (
662
+ cmd , values_dict = {'job' : self .id })
663
+ job = ProcessingJob .create (self .user , params )
664
+ # Doing the submission outside of the transaction
665
+ job .submit ()
666
+
622
667
def _set_validator_jobs (self , validator_jobs ):
623
668
"""Sets the validator jobs for the current job
624
669
@@ -673,15 +718,6 @@ def complete(self, success, artifacts_data=None, error=None):
673
718
else :
674
719
self ._set_status ('success' )
675
720
else :
676
- if self .command .software .type == 'artifact definition' :
677
- job_params = self .parameters .values
678
- if job_params .get ('provenance' ) is not None :
679
- # This artifact definition job is a result of a command
680
- # run, if it fails, set up the status of the "parent"
681
- # job also as failed, and assign the sem error message
682
- provenance = loads (job_params ['provenance' ])
683
- job = ProcessingJob (provenance ['job' ])
684
- job ._set_error (error )
685
721
self ._set_error (error )
686
722
687
723
@property
0 commit comments