Restricting a custom Drupal Rules action to execute once

Today I needed to apply some custom discounts to orders in Drupal Commerce. The Rules workflow is:

  1. Delete any existing discount line items from the order
  2. Calculate possible discounts and add new discount line items to the order
    1. I'm sure that there are other approaches, but this seemed simple (lol) and most importantly it seemed like it would satisfy my use case.

      The remove rule, and the calculate rules, all had the same event "After commerce order has been updated", with a condition that the order be a shopping cart order. This made sense, if someone updates their cart, then recalculate the discounts. The problem was that the rules were executed multiple times.

      Let's say that the user added an extra widget to their order, to which a custom discount applies.

      1. Add a widget to the order (causing the order to be updated)
      2. Remove all custom discount line items
      3. Calculate the new discount, and add a discount to the order (causing the order to be updated)
      4. Go back to step 2...

      Essentially what I wanted to do was force the Remove custom discounts rule action (which was a custom action) to only be executed once. I did not choose the most elegant way to solve this problem, and re-analyzing would have likely worked with the logic of a Rules component 'Rule set'.

      At the top of my Rules action handler I added a test, to make sure that the function would only execute once per bootstrap.

      function my_rules_action_handler($param1, $param2) {
        // Make sure this function only executes once.
        if ($executed = &drupal_static(__FUNCTION__) {
          return FALSE;
        else {
          $executed = TRUE;

        // Insert the code for the action.

      I'm not too happy with the solution, and hope to have the opportunity to revisit this in the future. Not every solution that we come up with as developers makes us happy, but the hope is that they all successfully satisfy the problem that we are attempting to solve.