Call for Testing - Enforcing Action Sequence

thebenrobb

Employee

16-11-2018

We're testing a new behavior with the way that rules execute in the browser.

This post will cover the problem we're solving, the solution that we'd like help testing, and the things you should watch out for as you test.  We'll then provide instructions for testing the behavior in your own browser as well as rolling it out to a portion (or all) of your audience.

1) The Problem

Currently, when a rule is triggered, Launch will execute the rule actions in order, but it does not wait for one to finish before the next one starts.

This can create problems when the rule action actually does something asynchronous.  This is most common in the case of custom code where the network retrieval of the custom code is done asynchronously, so subsequent actions are often completed before the custom code is retrieved and executed.

2) Solution in Testing

Turbine is Launch's client-side rules engine.  Turbine is currently shipping with a hidden behavior that you can enable.  Once enabled, rule conditions and rule actions will wait for the completion of the previous one before they begin execution.  This is accomplished through -- gratuitous techno-jargon warning -- converting rule conditions and rule actions into asynchronous promise chains.

Effectively, this creates a queue for rule conditions and actions.  When a rule is triggered, its conditions and actions are put into the queue.  When a single event triggers multiple rules, the conditions and actions for each rule will be put in the queue in the order dictated by the Rule Order field.

The queue is processed as quickly as possible.

Individual conditions and actions in the queue have a timeout of 2000ms.  When a component times out, all subsequent conditions and actions from that rule will be cancelled and processing will continue with the next rule.  There is no rule-level timeout.

3) Implications

Depending on how you're using Launch, there are some important implications that you should know about.  We'll cover these from most impactful to least.

3.1) All Conditions and Actions are Asynchronous

All conditions and actions are run asynchronously now.  If you are loading Launch synchronously and you have rules with Library Loaded or Page Bottom events, there is some risk you should know about.

Let's take the following scenario where:

  • I am loading Launch synchronously
  • I have a rule with a Library Load event and a Custom Code action that creates a global variable
  • I am loading Launch on my page with the following code -- you wouldn't do this, this is just for illustration:

<script src="//assets.adobedtm.com/staging/launch-ENab18ee4295ad48988ddb241e2794e906-development.min.js"></script>

<script>

  console.log(window.globalVariableCreatedFromMyCustomCodeInLaunch.foo);

</script>

Currently, your Custom Code action will be executed synchronously when the Library is loaded.  The global variable I created will exist before the browser continues on to call console.log().

With queuing enabled, my Custom Code action is executed asynchronously.  It will still get done very soon -- with the next JavaScript event loop -- but I have no guarantee that it will exist before I call console.log().

3.2) Queued When Called

Conditions and Actions are added to the end of the queue at the time they are called.  Let's take the scenario where I have Rule A and Rule B that both use the Library Loaded event.  They are ordered so that A will run before B, so all the conditions and actions for Rule A are added to the queue, then the conditions and actions for Rule B are added to the queue.

Rule A has an action that invokes Direct Call Rule C.  Rule C's conditions and actions are added to the queue when Rule A's action is executed, but they will be behind Rule B's conditions and actions in the queue.  Rule B will still run first.

This could lead to scenarios where Rule C is is being executed later than you might expect.

3.3) External Actions Can Influence Results

Because conditions and actions are now delayed by some extra amount, there is a higher possibility that external actors can interact with the data layer between the time that the rule is triggered and the rule conditions and actions are executed.

The consequence is that if you have conditions or actions that reference data on the data layer, they may be using newer/different data than what was on the data layer at the time the rule was initially triggered.

That may not be what you might expect.

3.4) Extension Support

In order for Launch to know what a condition or an action needs to perform an asynchronous task, the extension code must return a promise from the condition or action.  If the extension code does not return a promise, Launch will assume the condition or action is immediately finished and move on to the next item in the queue.

Currently, Core, Adobe Analytics, and Google Universal Analytics are compliant with returning promises.  Adobe Audience Manager and Adobe Target will be updated soon to also return these promises.  In the meantime, we suggest not testing the queueing within properties that use Audience Manager or Target extensions.

4) How to Test

I said before that Turbine is now shipping with this behavior and that you just need to enable it.  It is enabled by setting com.adobe.reactor.queue to true in either session or local storage.

Turbine will check this value each time a rule is triggered and will behave as directed.  Setting it in session storage will enable the behavior for the current browser session only.  Setting it in local storage will enable it for the current session and all future sessions until it is removed.

4.1) Enable In Your Own Browser

To test the behavior in your own browser only, simply open your browser console and run:

sessionStorage.setItem('com.adobe.reactor.queue', true);

or

localStorage.setItem('com.adobe.reactor.queue', true);

4.2) Disable In Your Own Browser

To disable the behavior in your own browser only, you can do the following in your console:

sessionStorage.removeItem('com.adobe.reactor.queue');

or

localStorage.removeItem('com.adobe.reactor.queue');

4.3) How to Enable for Your Audience

If you want to enable the behavior for some or all of your audience, you can set the local storage item with a Launch rule.  Your rule could look something like this:

Component Type
Component NameNotes
EventLibrary LoadedSet your rule order to -10000 or some other large negative number to force the rule to run before your other Library Loaded rules.
ConditionSamplingChoose the percentage of your audience that you would like to enable it for.  Be sure to check the Persist Cohort box.  You'll need to be on Core Extension 1.3.0 in order to persist cohorts.
EventCustom Code

sessionStorage.setItem('com.adobe.reactor.queue', true);

Add the rule to a library and publish it.  If you are really, really sure about what you're doing, and you want to give it to your entire audience, then simply skip the condition.  We recommend thorough testing before you go that far.  You may also want to consider setting an Analytics variable so you can segment reports by whether the end user got the queuing behavior or not.

4.4) How to Disable for Your Audience

To turn off the queuing behavior for your audience, simply disable the rule, add the disabled rule to a library and publish the library.  The sessionStorage key will not be set for the end-user on their next browser session and they'll get the non-queued behavior.

5) Feedback

If you've made it this far and you're interested (or even excited?!) about testing this behavior, then we are very interested in hearing the results of your testing, good or bad.  The purpose of this testing is to find out what happens when queueing is used in real-world scenarios, and to do that, we need your input from your real-world scenarios.  Please do not be shy about sharing your experiences.

5.1) Where To Go

To ask questions or give us feedback, please join the Launch Developers slack workspace (click here to join), then join the #action-sequence channel.  You may also leave feedback below, but Slack will get quicker responses.

5.2) Topics for Feedback

If you have strong opinions on any of the following, please reach out to let us know:

  1. Issues - What problems does queuing create for you?
  2. Timeout on items in the queue - Is 2000ms too long?  Is it too short?
  3. Timed out behavior - Do you have use cases where you want subsequent actions on a rule to continue to fire even if a condition or previous action times out?
  4. Rollout - Is this so beautiful that we should just switch all rules over to use this new behavior, or do you need more conditional control?

Happy testing, please let us know how it goes 😃