59
59
from cylc .task_job_mgr import TaskJobManager
60
60
from cylc .task_pool import TaskPool
61
61
from cylc .task_proxy import TaskProxy , TaskProxySequenceBoundsError
62
- from cylc .task_state import TASK_STATUSES_ACTIVE , TASK_STATUS_FAILED
62
+ from cylc .task_state import (
63
+ TASK_STATUSES_ACTIVE , TASK_STATUSES_NEVER_ACTIVE , TASK_STATUS_FAILED )
63
64
from cylc .templatevars import load_template_vars
64
65
from cylc .version import CYLC_VERSION
65
66
from cylc .wallclock import (
66
- get_current_time_string , get_seconds_as_interval_string )
67
+ get_current_time_string , get_seconds_as_interval_string ,
68
+ get_time_string_from_unix_time as time2str )
67
69
from cylc .profiler import Profiler
68
70
69
71
@@ -133,15 +135,15 @@ def __init__(self, is_restart, options, args):
133
135
self .config = None
134
136
135
137
self .is_restart = is_restart
136
- self ._cli_initial_point_string = None
137
- self ._cli_start_point_string = None
138
+ self .cli_initial_point_string = None
139
+ self .cli_start_point_string = None
138
140
start_point_str = None
139
141
if len (args ) > 1 :
140
142
start_point_str = args [1 ]
141
143
if getattr (self .options , 'warm' , None ):
142
- self ._cli_start_point_string = start_point_str
144
+ self .cli_start_point_string = start_point_str
143
145
else :
144
- self ._cli_initial_point_string = start_point_str
146
+ self .cli_initial_point_string = start_point_str
145
147
self .template_vars = load_template_vars (
146
148
self .options .templatevars , self .options .templatevars_file )
147
149
@@ -382,16 +384,7 @@ def configure(self):
382
384
self .load_tasks_for_run ()
383
385
self .profiler .log_memory ("scheduler.py: after load_tasks" )
384
386
385
- self .suite_db_mgr .put_suite_params (
386
- CYLC_VERSION ,
387
- self .task_job_mgr .task_remote_mgr .uuid_str ,
388
- self .run_mode ,
389
- str (cylc .flags .utc ),
390
- self .initial_point ,
391
- self .final_point ,
392
- self .pool .is_held ,
393
- self .config .cfg ['cylc' ]['cycle point format' ],
394
- self ._cli_start_point_string )
387
+ self .suite_db_mgr .put_suite_params (self )
395
388
self .suite_db_mgr .put_suite_template_vars (self .template_vars )
396
389
self .suite_db_mgr .put_runtime_inheritance (self .config )
397
390
self .configure_suite_environment ()
@@ -446,8 +439,8 @@ def load_tasks_for_restart(self):
446
439
"""Load tasks for restart."""
447
440
self .suite_db_mgr .pri_dao .select_suite_params (
448
441
self ._load_suite_params_2 , self .options .checkpoint )
449
- if self ._cli_start_point_string :
450
- self .start_point = self ._cli_start_point_string
442
+ if self .cli_start_point_string :
443
+ self .start_point = self .cli_start_point_string
451
444
self .suite_db_mgr .pri_dao .select_broadcast_states (
452
445
self .task_events_mgr .broadcast_mgr .load_db_broadcast_states ,
453
446
self .options .checkpoint )
@@ -901,15 +894,7 @@ def command_reload_suite(self):
901
894
self .configure_suite_environment ()
902
895
if self .options .genref or self .options .reftest :
903
896
self .configure_reftest (recon = True )
904
- self .suite_db_mgr .put_suite_params (
905
- CYLC_VERSION ,
906
- self .task_job_mgr .task_remote_mgr .uuid_str ,
907
- self .run_mode ,
908
- str (cylc .flags .utc ),
909
- self .initial_point ,
910
- self .final_point ,
911
- self .pool .is_held ,
912
- self .config .cfg ['cylc' ]['cycle point format' ])
897
+ self .suite_db_mgr .put_suite_params (self )
913
898
cylc .flags .iflag = True
914
899
915
900
def set_suite_timer (self ):
@@ -993,8 +978,8 @@ def load_suiterc(self, is_reload=False):
993
978
self .config = SuiteConfig (
994
979
self .suite , self .suiterc , self .template_vars ,
995
980
run_mode = self .run_mode ,
996
- cli_initial_point_string = self ._cli_initial_point_string ,
997
- cli_start_point_string = self ._cli_start_point_string ,
981
+ cli_initial_point_string = self .cli_initial_point_string ,
982
+ cli_start_point_string = self .cli_start_point_string ,
998
983
cli_final_point_string = self .options .final_point_string ,
999
984
is_reload = is_reload ,
1000
985
mem_log_func = self .profiler .log_memory ,
@@ -1044,17 +1029,17 @@ def load_suiterc(self, is_reload=False):
1044
1029
self .run_mode = self .config .run_mode
1045
1030
1046
1031
def _load_suite_params_1 (self , _ , row ):
1047
- """Load previous initial/ start cycle point.
1032
+ """Load previous initial cycle point or (warm) start cycle point.
1048
1033
1049
- For restart, it may be missing from "suite.rc", but was specified as a
1050
- command line argument on cold/warm start.
1034
+ For restart, these may be missing from "suite.rc", but was specified as
1035
+ a command line argument on cold/warm start.
1051
1036
"""
1052
1037
key , value = row
1053
- if key == ' initial_point' :
1054
- self ._cli_initial_point_string = value
1038
+ if key == " initial_point" :
1039
+ self .cli_initial_point_string = value
1055
1040
self .task_events_mgr .pflag = True
1056
- elif key == ' warm_point' :
1057
- self ._cli_start_point_string = value
1041
+ elif key in [ "start_point" , " warm_point" ] :
1042
+ self .cli_start_point_string = value
1058
1043
self .task_events_mgr .pflag = True
1059
1044
elif key == 'uuid_str' :
1060
1045
self .task_job_mgr .task_remote_mgr .uuid_str = str (value )
@@ -1245,6 +1230,22 @@ def database_health_check(self):
1245
1230
# Something has to be very wrong here, so stop the suite
1246
1231
raise SchedulerError (str (exc ))
1247
1232
1233
+ def late_tasks_check (self ):
1234
+ """Report tasks that are late for their clock triggers."""
1235
+ now = time ()
1236
+ for itask in self .pool .get_tasks ():
1237
+ if (not itask .is_late and itask .get_late_time () and
1238
+ itask .state .status in TASK_STATUSES_NEVER_ACTIVE and
1239
+ now > itask .get_late_time ()):
1240
+ msg = '%s (late-time=%s)' % (
1241
+ self .task_events_mgr .EVENT_LATE ,
1242
+ time2str (itask .get_late_time ()))
1243
+ itask .is_late = True
1244
+ LOG .warning (msg , itask = itask )
1245
+ self .task_events_mgr .setup_event_handlers (
1246
+ itask , self .task_events_mgr .EVENT_LATE , msg )
1247
+ self .suite_db_mgr .put_insert_task_late_flags (itask )
1248
+
1248
1249
def timeout_check (self ):
1249
1250
"""Check suite and task timers."""
1250
1251
self .check_suite_timer ()
@@ -1373,8 +1374,9 @@ def run(self):
1373
1374
1374
1375
# PROCESS ALL TASKS whenever something has changed that might
1375
1376
# require renegotiation of dependencies, etc.
1376
- if self .process_tasks ():
1377
+ if self .should_process_tasks ():
1377
1378
self .process_task_pool ()
1379
+ self .late_tasks_check ()
1378
1380
1379
1381
self .process_queued_task_messages ()
1380
1382
self .process_command_queue ()
@@ -1481,22 +1483,13 @@ def check_suite_stalled(self):
1481
1483
if self ._get_events_conf (self .EVENT_TIMEOUT ):
1482
1484
self .set_suite_timer ()
1483
1485
1484
- def process_tasks (self ):
1486
+ def should_process_tasks (self ):
1485
1487
"""Return True if waiting tasks are ready."""
1486
1488
# do we need to do a pass through the main task processing loop?
1487
1489
process = False
1488
1490
1489
- # External triggers must be matched now. If any are matched pflag
1490
- # is set to tell process_tasks() that task processing is required.
1491
- broadcast_mgr = self .task_events_mgr .broadcast_mgr
1492
- broadcast_mgr .add_ext_triggers (self .ext_trigger_queue )
1493
- for itask in self .pool .get_tasks ():
1494
- if (itask .state .external_triggers and
1495
- broadcast_mgr .match_ext_trigger (itask )):
1496
- process = True
1497
-
1498
1491
if self .task_events_mgr .pflag :
1499
- # this flag is turned on by commands that change task state
1492
+ # This flag is turned on by commands that change task state
1500
1493
process = True
1501
1494
self .task_events_mgr .pflag = False # reset
1502
1495
@@ -1505,10 +1498,18 @@ def process_tasks(self):
1505
1498
process = True
1506
1499
self .task_job_mgr .task_remote_mgr .ready = False # reset
1507
1500
1508
- self .pool .set_expired_tasks ()
1509
- if self .pool .waiting_tasks_ready ():
1510
- process = True
1511
-
1501
+ broadcast_mgr = self .task_events_mgr .broadcast_mgr
1502
+ broadcast_mgr .add_ext_triggers (self .ext_trigger_queue )
1503
+ now = time ()
1504
+ for itask in self .pool .get_tasks ():
1505
+ # External trigger matching and task expiry must be done
1506
+ # regardless, so they need to be in separate "if ..." blocks.
1507
+ if broadcast_mgr .match_ext_trigger (itask ):
1508
+ process = True
1509
+ if self .pool .set_expired_task (itask , now ):
1510
+ process = True
1511
+ if itask .is_ready (now ):
1512
+ process = True
1512
1513
if self .run_mode == 'simulation' and self .pool .sim_time_check (
1513
1514
self .message_queue ):
1514
1515
process = True
0 commit comments