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 []")