Sitecore Commerce 9: MinionDelayPolicy

Andrei Paliakou on December 4, 2018

While finishing order feature implementation for my current project I found one strange error message in commerce logs:

ERROR PipelineAbort:Orders.block.ValidatePendingOrder: Order 'Entity-Order-6d0f7501af7342c6b4534a18449f8abe' has MinionDelayPolicy: Delay=180

Ok…pipeline was aborted, because MinionDelayPolicy has delay for 180 seconds. It was a surprise for me, because I expect that my order processing will be done immediately without any delays.

Sitecore Commerce 9: MinionDelayPolicy and PipelineAbort:Orders.block.ValidatePendingOrder: Order has MinionDelayPolicy: Delay=180

I started investigate why I have this delay and found MinionDelayPolicy:

 public class MinionDelayPolicy : Policy
  {
    public MinionDelayPolicy()
    {
      this.ReleaseDelaySeconds = 180;
      this.CompleteDelaySeconds = 420;
      this.LogDelays = false;
      this.ZeroDelayRoleTrigger = "ZeroMinionDelay";
    }

    public int ReleaseDelaySeconds { get; set; }

    public int CompleteDelaySeconds { get; set; }

    public bool LogDelays { get; set; }

    public string ZeroDelayRoleTrigger { get; set; }
  }

As you can see, by default we have two delays for release and complete orders. But also in this policy we have any property ZeroDelayRoleTrigger, which has value “ZeroMinionDelay”.

My error was throw by ValidatePendingOrderBlock:

[PipelineDisplayName("Orders.block.ValidatePendingOrder")]
  public class ValidatePendingOrderBlock : PipelineBlock<PendingOrdersMinionArgument, Order, CommercePipelineExecutionContext>
  {
    private readonly IFindEntityPipeline _findEntityPipeline;

    public ValidatePendingOrderBlock(IFindEntityPipeline findEntityPipeline)
    {
      this._findEntityPipeline = findEntityPipeline;
    }

    public override async Task<Order> Run(PendingOrdersMinionArgument arg, CommercePipelineExecutionContext context)
    {
      
      MinionDelayPolicy minionDelayPolicy = order.HasPolicy<MinionDelayPolicy>() ? order.GetPolicy<MinionDelayPolicy>() : context.GetPolicy<MinionDelayPolicy>();
      DateTimeOffset? dateCreated = order.DateCreated;
      if (dateCreated.HasValue)
      {
        dateCreated = order.DateCreated;
        if (DateTimeOffset.Compare(dateCreated.Value.AddSeconds((double) minionDelayPolicy.ReleaseDelaySeconds), DateTimeOffset.UtcNow) > 0)
        {
          if (minionDelayPolicy.LogDelays)
          {
            context.Logger.LogInformation(string.Format("{0}: Ignoring pending order '{1}' not yet ready to be released due to MinionDelayPolicy={2}", (object) __nonvirtual (pendingOrderBlock.Name), (object) order.Id, (object) minionDelayPolicy.ReleaseDelaySeconds), Array.Empty<object>());
          }

          context.Abort(string.Format("{0}: Order '{1}' has MinionDelayPolicy: Delay={2}", (object) __nonvirtual (pendingOrderBlock.Name), (object) order.Id, (object) minionDelayPolicy.ReleaseDelaySeconds), (object) context);
          return order;
        }
      }
      return order;
    }
  }

It means that by default it will Ignore pending order, because order isn’t yet ready to be released due to MinionDelayPolicy.

Also I found that OrderPlacedZeroMinionDelayBlock uses MinionDelayPolicy:

[PipelineDisplayName("Orders.block.OrderPlacedZeroMinionDelay")]
  public class OrderPlacedZeroMinionDelayBlock : PipelineBlock<Order, Order, CommercePipelineExecutionContext>
  {
    public override Task<Order> Run(Order order, CommercePipelineExecutionContext context)
    {
      Condition.Requires<Order>(order).IsNotNull<Order>("The order can not be null");
      MinionDelayPolicy delayPolicyContext = context.GetPolicy<MinionDelayPolicy>();
      if (context.CommerceContext.PolicyKeys().All<string>((Func<string, bool>) (p => p != delayPolicyContext.ZeroDelayRoleTrigger)))
        return Task.FromResult<Order>(order);
      MinionDelayPolicy policy = order.GetPolicy<MinionDelayPolicy>();
      policy.CompleteDelaySeconds = 0;
      policy.ReleaseDelaySeconds = 0;
      return Task.FromResult<Order>(order);
    }
  }

This OrderPlacedZeroMinionDelayBlock can disable delays, if we will have in the request headers PolicyKeys= ZeroMinionDelay

commerce MinionDelayPolicy

This small trick can disable delays for order processing if you need.