diff --git a/doc/cug.tex b/doc/cug.tex index f40fcfa2a61..1693ff0f4b0 100644 --- a/doc/cug.tex +++ b/doc/cug.tex @@ -3348,23 +3348,12 @@ \subsubsection{Trigger Types} \paragraph{Message Triggers} \label{MessageTriggers} -Message triggers allow triggering off custom messages emitted by a task as it -runs. {\em Message outputs} must be registered for the task in the suite -definition, and matching messages sent back to the suite daemon by the -task at the appropriate time. {\em Note that polling does not yet detect custom -message output completion.} Custom output messages should normally contain the -cycle point in order to -distinguish between the outputs of different instances of the same task. -The task implementation can use \lstinline=$CYLC_TASK_CYCLE_POINT= for -this, or \lstinline@cylc cycle-point --offset=P2M@ for an offset value. -The matching message string registered in the suite definition, however, does -not get interpreted by the shell, so a cycle point placeholder is used instead: -\lstinline=[]= for the current cycle point, or for an offset \lstinline=[-P2M]=. - -The \lstinline=$CYLC_DIR/examples/message-triggers/= suite is a self-contained -example that illustrates message triggering. Note that the graph trigger -notation uses a label that selects the message registered under the task -\lstinline=[runtime]= section. +Tasks can also trigger off custom output messages. These must be registered in +the \lstinline=[runtime]= section of the emitting task, and reported using the +\lstinline=cylc message= command in task scripting. The graph trigger notation +refers to the item name of the registered output message. +The example suite \lstinline=$CYLC_DIR/examples/message-triggers= illustrates +message triggering. \lstset{language=suiterc} \lstinputlisting{../examples/message-triggers/suite.rc} diff --git a/doc/suiterc.tex b/doc/suiterc.tex index 7cf1535bc96..35739de7285 100644 --- a/doc/suiterc.tex +++ b/doc/suiterc.tex @@ -1706,26 +1706,23 @@ \subsection{[runtime]} \paragraph[{[[[}outputs{]]]}]{[runtime] \textrightarrow [[\_\_NAME\_\_]] \textrightarrow [[[outputs]]]} -This section is for registering custom message outputs that other tasks can -trigger off instead of the standard triggers. The task implementation must send -corresponding messages using the \lstinline=cylc task message= command at the -appropriate time. See~\ref{MessageTriggers} for more information. +Register custom task outputs for use in message triggering in this section +(\ref{MessageTriggers}) \subparagraph[\_\_OUTPUT\_\_ ]{[runtime] \textrightarrow [[\_\_NAME\_\_]] \textrightarrow [[[outputs]]] \textrightarrow \_\_OUTPUT\_\_} -Replace \_\_OUTPUT\_\_ with one or more labelled output messages, and use the -labels in graph trigger notation. Messages should contain a placeholder for -the current cycle point (\lstinline=[]=) or some offset from it (e.g.\ \lstinline=[-P2M]=). +Replace \_\_OUTPUT\_\_ with one or more custom task output messages +(\ref{MessageTriggers}). The item name is used to select the custom output +message in graph trigger notation. \begin{myitemize} \item {\em type:} string \item {\em default:} (none) \item{ \em examples:} \end{myitemize} \begin{lstlisting} -foo = "sea state products ready for []" -bar = "nwp restart files ready for [-PT6H]" +out1 = "sea state products ready" +out2 = "NWP restart files completed" \end{lstlisting} -See~\ref{MessageTriggers} for more information. \paragraph[{[[[}suite state polling{]]]}]{[runtime] \textrightarrow [[\_\_NAME\_\_]] \textrightarrow [[[suite state polling]]]} diff --git a/examples/message-triggers/suite.rc b/examples/message-triggers/suite.rc index 64b0829f4ae..47f2fb42d66 100644 --- a/examples/message-triggers/suite.rc +++ b/examples/message-triggers/suite.rc @@ -5,23 +5,18 @@ title = "test suite for cylc-6 message triggers" final cycle point = 20141201T00 [[dependencies]] [[[P2M]]] - graph = """ -# bar triggers off message 'x' emitted by foo: - foo:x => bar -# baz triggers off message 'y' emitted by the previous instance of foo: - foo[-P2M]:y => baz - """ + graph = """foo:out1 => bar + foo[-P2M]:out2 => baz""" [runtime] [[foo]] script = """ -echo HELLO -sleep 2 -TARGET_POINT=$CYLC_TASK_CYCLE_POINT -cylc message "file 1 for $TARGET_POINT done" -sleep 2 -TARGET_POINT=$(cylc cycle-point --offset P2M) -cylc message "file 2 for $TARGET_POINT done" -sleep 2""" +sleep 5 +cylc message "file 1 done" +sleep 10 +cylc message "file 2 done" +sleep 10""" [[[outputs]]] - x = "file 1 for [] done" - y = "file 2 for [P2M] done" + out1 = "file 1 done" + out2 = "file 2 done" + [[bar, baz]] + script = sleep 10 diff --git a/lib/cylc/config.py b/lib/cylc/config.py index 40da4177bd0..ff567867a0d 100644 --- a/lib/cylc/config.py +++ b/lib/cylc/config.py @@ -1699,15 +1699,6 @@ def generate_taskdefs(self, line, left_nodes, right, section, seq, # Record message outputs. for lbl, msg in self.cfg['runtime'][name]['outputs'].items(): outp = output(msg, base_interval) - # Check for a cycle offset placeholder. - # TODO - DEPRECATE OUTPUT OFFSET PLACEHOLDERS - if not re.search(r'\[[^\]]*\]', msg): - print >> sys.stderr, ( - "Message outputs require an " - "offset placeholder (e.g. '[]' or '[-P2M]'):") - print >> sys.stderr, " %s = %s" % (lbl, msg) - raise SuiteConfigError( - 'ERROR: bad message output string') if outp not in self.taskdefs[name].outputs: self.taskdefs[name].outputs.append(outp) diff --git a/lib/cylc/output.py b/lib/cylc/output.py index b3d4f041c09..9f590ddc39d 100644 --- a/lib/cylc/output.py +++ b/lib/cylc/output.py @@ -18,7 +18,7 @@ import re from cycling.loader import get_interval, get_interval_cls -from trigger import BACK_COMPAT_MSG_RE, MSG_RE +from trigger import get_message_offset class output(object): @@ -33,27 +33,8 @@ class output(object): """ def __init__(self, msg, base_interval=None): - self.msg_offset = None self.msg = msg - m = re.match(BACK_COMPAT_MSG_RE, self.msg) - if m: - # Old-style offset - prefix, signed_offset, sign, offset, suffix = m.groups() - if signed_offset is not None: - self.msg_offset = base_interval.get_inferred_child( - signed_offset) - else: - n = re.match(MSG_RE, msg) - if n: - # New-style offset - prefix, signed_offset, sign, offset, suffix = n.groups() - if offset: - self.msg_offset = get_interval(signed_offset) - else: - self.msg_offset = get_interval_cls().get_null() - else: - # Plain message, no offset. - pass + self.msg_offset = get_message_offset(msg, base_interval) def get(self, point): new_point = point diff --git a/lib/cylc/trigger.py b/lib/cylc/trigger.py index d87aacdd7c2..c747182aeda 100644 --- a/lib/cylc/trigger.py +++ b/lib/cylc/trigger.py @@ -17,6 +17,7 @@ # along with this program. If not, see . import re +import sys from cylc.task_id import TaskID from cylc.cycling.loader import ( @@ -24,8 +25,43 @@ from cylc.task_state import TaskState, TaskStateError -BACK_COMPAT_MSG_RE = re.compile('^(.*)\[\s*T\s*(([+-])\s*(\d+))?\s*\](.*)$') -MSG_RE = re.compile('^(.*)\[\s*(([+-])?\s*(.*))?\s*\](.*)$') +warned = False + + +def get_message_offset(msg, base_interval=None): + """Return back-compat message offset, or None.""" + + BACK_COMPAT_MSG_RE_OLD = re.compile('^(.*)\[\s*T\s*(([+-])\s*(\d+))?\s*\](.*)$') + BACK_COMPAT_MSG_RE = re.compile('^(.*)\[\s*(([+-])?\s*(.*))?\s*\](.*)$') + DEPRECATION_TEMPLATE = "WARNING: message trigger offsets are deprecated\n %s" + + offset = None + global warned + + # cylc-5 [T+n] message offset - DEPRECATED + m = re.match(BACK_COMPAT_MSG_RE_OLD, msg) + if m: + if not warned: + print >> sys.stderr, DEPRECATION_TEMPLATE % msg + warned = True + prefix, signed_offset, sign, offset, suffix = m.groups() + if signed_offset is not None: + offset = base_interval.get_inferred_child( + signed_offset) + else: + # cylc-6 [] message offset - DEPRECATED + n = re.match(BACK_COMPAT_MSG_RE, msg) + if n: + if not warned: + print >> sys.stderr, DEPRECATION_TEMPLATE % msg + warned = True + prefix, signed_offset, sign, offset, suffix = n.groups() + if offset: + offset = get_interval(signed_offset) + else: + offset = get_interval_cls().get_null() + # else: Plain message, no offset. + return offset class TriggerError(Exception): @@ -50,9 +86,9 @@ class trigger(object): [runtime] [[foo]] [[[outputs]]] - x = "file X uploaded for [P1D]" - y = "file Y uploaded for []" - """ + x = "file X uploaded" + y = "file Y finished" + """ def __init__( self, task_name, qualifier=None, graph_offset_string=None, @@ -78,39 +114,14 @@ def __init__( # Message trigger? try: - msg = outputs[qualifier] + self.message = outputs[qualifier] except KeyError: raise TriggerError( "ERROR: undefined trigger qualifier: %s:%s" % ( task_name, qualifier)) else: - # Back compat for [T+n] in message string. - m = re.match(BACK_COMPAT_MSG_RE, msg) - msg_offset = None - if m: - prefix, signed_offset, sign, offset, suffix = m.groups() - if offset: - msg_offset = base_interval.get_inferred_child( - signed_offset) - else: - msg_offset = get_interval_cls().get_null() - else: - n = re.match(MSG_RE, msg) - if n: - prefix, signed_offset, sign, offset, suffix = n.groups() - if offset: - msg_offset = get_interval(signed_offset) - else: - msg_offset = get_interval_cls().get_null() - else: - raise TriggerError( - "ERROR: undefined trigger qualifier: %s:%s" % ( - task_name, qualifier)) - self.message = msg - self.message_offset = msg_offset - - def is_standard(self): - return self.builtin is not None + self.message_offset = get_message_offset(self.message, + base_interval) def get_prereq(self, point): """Return a prerequisite string.""" diff --git a/tests/message-triggers/00-old.t b/tests/message-triggers/00-cylc5-dep.t similarity index 100% rename from tests/message-triggers/00-old.t rename to tests/message-triggers/00-cylc5-dep.t diff --git a/tests/message-triggers/00-old/reference.log b/tests/message-triggers/00-cylc5-dep/reference.log similarity index 100% rename from tests/message-triggers/00-old/reference.log rename to tests/message-triggers/00-cylc5-dep/reference.log diff --git a/tests/message-triggers/00-old/suite.rc b/tests/message-triggers/00-cylc5-dep/suite.rc similarity index 91% rename from tests/message-triggers/00-old/suite.rc rename to tests/message-triggers/00-cylc5-dep/suite.rc index 95454b917ee..bdf002c44e0 100644 --- a/tests/message-triggers/00-old/suite.rc +++ b/tests/message-triggers/00-cylc5-dep/suite.rc @@ -1,4 +1,4 @@ -title = "test suite for pre cylc-6 message triggers" +title = "test suite for deprecated cylc-5 message triggers" [cylc] [[reference test]] diff --git a/tests/message-triggers/01-new.t b/tests/message-triggers/01-cylc6-dep.t similarity index 100% rename from tests/message-triggers/01-new.t rename to tests/message-triggers/01-cylc6-dep.t diff --git a/tests/message-triggers/01-new/reference.log b/tests/message-triggers/01-cylc6-dep/reference.log similarity index 100% rename from tests/message-triggers/01-new/reference.log rename to tests/message-triggers/01-cylc6-dep/reference.log diff --git a/tests/message-triggers/01-new/suite.rc b/tests/message-triggers/01-cylc6-dep/suite.rc similarity index 92% rename from tests/message-triggers/01-new/suite.rc rename to tests/message-triggers/01-cylc6-dep/suite.rc index fa656753b45..63417b6ad98 100644 --- a/tests/message-triggers/01-new/suite.rc +++ b/tests/message-triggers/01-cylc6-dep/suite.rc @@ -1,4 +1,4 @@ -title = test suite for cylc-6 message triggers +title = test suite for deprecated cylc-6 message triggers [cylc] UTC mode = True [[reference test]] diff --git a/tests/message-triggers/03-placeholder.t b/tests/message-triggers/03-new-style.t similarity index 81% rename from tests/message-triggers/03-placeholder.t rename to tests/message-triggers/03-new-style.t index 83136bf2b3f..18ae90da9e3 100644 --- a/tests/message-triggers/03-placeholder.t +++ b/tests/message-triggers/03-new-style.t @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . #------------------------------------------------------------------------------- -# Test validation fails message outputs with no cycle offset placeholder. +# Test new-style simplified message triggers (see GitHub #1761) . $(dirname $0)/test_header #------------------------------------------------------------------------------- set_test_number 2 @@ -23,7 +23,9 @@ set_test_number 2 install_suite $TEST_NAME_BASE $TEST_NAME_BASE #------------------------------------------------------------------------------- TEST_NAME=$TEST_NAME_BASE-validate -run_fail $TEST_NAME cylc validate $SUITE_NAME -grep_ok 'ERROR: bad message output string' $TEST_NAME.stderr +run_ok $TEST_NAME cylc validate $SUITE_NAME +#------------------------------------------------------------------------------- +TEST_NAME=$TEST_NAME_BASE-run +suite_run_ok $TEST_NAME cylc run --reference-test --debug $SUITE_NAME #------------------------------------------------------------------------------- purge_suite $SUITE_NAME diff --git a/tests/message-triggers/03-new-style/reference.log b/tests/message-triggers/03-new-style/reference.log new file mode 100644 index 00000000000..fdca23aa395 --- /dev/null +++ b/tests/message-triggers/03-new-style/reference.log @@ -0,0 +1,15 @@ +2016-03-15T12:15:44+13 INFO - Suite starting on niwa-34403.niwa.local:7766 +2016-03-15T12:15:44+13 INFO - Run mode: live +2016-03-15T12:15:44+13 INFO - Initial point: 20140801T0000+13 +2016-03-15T12:15:44+13 INFO - Final point: 20141201T0000+13 +2016-03-15T12:15:44+13 INFO - Cold Start 20140801T0000+13 +2016-03-15T12:15:44+13 INFO - [baz.20140801T0000+13] -triggered off [] +2016-03-15T12:15:44+13 INFO - [foo.20140801T0000+13] -triggered off [] +2016-03-15T12:15:46+13 INFO - [foo.20141001T0000+13] -triggered off [] +2016-03-15T12:15:48+13 INFO - [bar.20140801T0000+13] -triggered off ['foo.20140801T0000+13'] +2016-03-15T12:15:49+13 INFO - [foo.20141201T0000+13] -triggered off [] +2016-03-15T12:15:50+13 INFO - [baz.20141001T0000+13] -triggered off ['foo.20140801T0000+13'] +2016-03-15T12:15:50+13 INFO - [bar.20141001T0000+13] -triggered off ['foo.20141001T0000+13'] +2016-03-15T12:15:53+13 INFO - [baz.20141201T0000+13] -triggered off ['foo.20141001T0000+13'] +2016-03-15T12:15:53+13 INFO - [bar.20141201T0000+13] -triggered off ['foo.20141201T0000+13'] +2016-03-15T12:15:58+13 INFO - Suite shutting down at 2016-03-15T12:15:58+13 diff --git a/tests/message-triggers/03-new-style/suite.rc b/tests/message-triggers/03-new-style/suite.rc new file mode 100644 index 00000000000..7a9d80f294c --- /dev/null +++ b/tests/message-triggers/03-new-style/suite.rc @@ -0,0 +1,22 @@ +title = "test suite for cylc-6 message triggers" + +[scheduling] + initial cycle point = 20140801T00 + final cycle point = 20141201T00 + [[dependencies]] + [[[P2M]]] + graph = """foo:out1 => bar + foo[-P2M]:out2 => baz""" +[runtime] + [[foo]] + script = """ +sleep 2 +cylc message "file 1 done" +sleep 2 +cylc message "file 2 done" +sleep 2""" + [[[outputs]]] + out1 = "file 1 done" + out2 = "file 2 done" + [[bar, baz]] + script = /bin/true diff --git a/tests/message-triggers/03-placeholder/suite.rc b/tests/message-triggers/03-placeholder/suite.rc deleted file mode 100644 index db16b27bd57..00000000000 --- a/tests/message-triggers/03-placeholder/suite.rc +++ /dev/null @@ -1,12 +0,0 @@ -[scheduling] - cycling mode = integer - initial cycle point = 1 - [[dependencies]] - [[[P1]]] - graph = foo:x => bar -[runtime] - [[foo]] - script = cylc message "hello to $CYLC_TASK_CYCLE_POINT" - [[[outputs]]] - x = "hello to Bob" - # (should be "hello to []")