Why doesn't body action if_elapsed work with vars type promises?

Let's start with the details of body action if_elapsed.

1
2
3
4
5
6
7
  body action if_elapsed(x)
  # @brief Evaluate the promise every `x` minutes
  # @param x The time in minutes between promise evaluations
  {
        ifelapsed => "$(x)";
        expireafter => "$(x)";
  }
body action if_elapsed from the standard library

The ifelapsed action body attribute is the number of minutes before next allowed assessment of a promise. It overrides body agent control ifelapsed which defaults to 1 minute. It's intended to prevent overload due to unintentional resource consumption, but it can be used to control frequency. The expireafter action body attribute is the number of minutes a promise is allowed to run before the agent is subject to termination.

So the if_elapsed action body is saying that once the promise has been verified as having an outcome of kept or repaired it should remain locked for x minutes. The agent should not try to re-verify it until that lock is no longer valid. Additionally if another agent sees that an agent is still executing the promise after x minutes then the apparently stuck agent should be terminated.

In cfengine a promise is locked once it is seen to be kept or repaired. By default promises are locked for 1 minute. Until a lock expires the promise will be skipped. In this example, there are two promises. One promise to report the date, and one promise to report Hello. The date will be different each time the agent is run so the promise lock will not be the same between two agent runs and thus it will not be affected by promise locking.

1
2
3
4
5
6
7
8
  bundle agent main
  {
     reports:
       "$(sys.date)";
       "Hello";
       "Infrequent hello"
        action => if_elapsed( "5" );
  }
Example illustrating promise locking

Here are the results of several executions of cf-agent -f /tmp/example.cf.

R: Sat Dec 23 09:53:57 2017
R: Hello
R: Infrequent hello
Example illustrating promise locking first run
R: Sat Dec 23 09:54:19 2017
Example illustrating promise locking second run
R: Sat Dec 23 09:54:59 2017
R: Hello
Example illustrating promise locking third run
R: Sat Dec 23 09:55:14 2017
Example illustrating promise locking fourth run
R: Sat Dec 23 09:55:59 2017
R: Hello
Example illustrating promise locking fifth run
R: Sat Dec 23 10:38:03 2017
R: Hello
R: Infrequent hello
Example illustrating promise locking sixth run

vars type promises do not participate in promise locking and as such can not be affected by the ifelapsed action body attribute or the ifelapsed agent control attribute.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  bundle agent main
  {
    vars:
        "msg" string => "Hello World";
      
    reports:

        "$(sys.date)";

        "$(msg)"
          action => immediate;
  }
Example illustrating vars don't participate in locking

Here are the results of a couple runs ( cf-agent -f /tmp/vars-are-not-locked.cf ).

R: Tue Dec 26 13:03:15 2017
R: Hello World

Another run a few seconds later:

R: Tue Dec 26 13:03:28 2017
R: Hello World

We can see that Hello World was reported in both runs. It was only reported because we attached body action immediate to the reports promise. Note the vars promise did not require body action immediate in order for the variable msg to hold the value Hello World.