Plugins recursion – how can you handle it?

By | December 29, 2017

 

What if you register a plugin step on update of some attribute, and, then, update the same attribute in the plugin again?

clip_image001

Dynamics can’t decide, for you, when is the right time to stop this endless loop, but it will detect the recursion, and, after a few repetitions, will stop it:

clip_image003

It will do the same in many different situations. It can be one plugin, or a chain of plugins, or a chain of workflows, or a mix of those. They can be synchronous or a-synchronous, they just have to be executing as a result of the same original operation. There are some finer settings (which you can’t easily change, especially in the online environments) which control when Dynamics will interfere, but, in the end, as soon as the number of those sequential plugins/workflows reach a certain limit within a pre-defined timeframe, you will get a similar error message.

There are a few optimizations/workarounds available to you:

– Always define specific triggering attributes for your steps. Don’t just leave “all attributes” there. That way, you will reduce the possibility of occasional recursion, but you won’t be able to completely avoid it

– You can use context.Depth property which is available in the plugin execution context. It will keep increasing for every new workflow/plugin in the “chain”. For every new “update”, Depth will start with 1. Then, if, inside the first plugin step you do something that start another plugin, that second plugin will have Depth=2 in the context. And it will keep increasing till it reaches the point where Dynamics will interrupt the process. Although, keep in mind that those have to be sequential events where one event is causing the other. If, for instance, there are two pre-operation steps on Update of the same entity, both responding to the update of the same attributes, “Depth” will be the same in those two steps(since, from the Depth perspective, they are “parallel”.. not sequential). This is why you will often see this condition in the plugins:

if (context.Depth > 1) return;

That works, but that introduces a hidden problem. Imagine that you have a plugin that’s doing something on update and that has that kind of condition. You have deployed the plugin, you have tested it by opening the entity in Dynamics, updating a field, and verifying that the plugin kicked in. It is depth 1, so it’s all good:

clip_image005

But what if we change it a little?

clip_image007

Now it’s, suddenly, Depth 2, and the plugin will not kick in when the update happens from a workflow/another plugin. Which you may or may not discover until such time when somebody has created a workflow, started to use it, and, then, somebody else pointed out that the data is not consistent anymore

– Do not make the beginner’s mistake

Never do this:

Entity entity = (Entity)context.InputParameters[“Target”];

service.Update(entity);

Instead, always create a new in-memory entity, assign the id, and set only the attributes you want to update:

Entity entity = (Entity)context.InputParameters[“Target”];

Entity updatedEntity = new Entity(entity.LogicalName);

updatedEntity.Id = entity.Id;

updatedEntity[“attribute”] = value;

service.Update(updatedEntity);

– Try not to call service.Update at all – in the pre-operation step, you can use Target to set the attributes. There is no need for a separate Update call, and, if there is no such call, there is no recursion at all:

Entity entity = (Entity)context.InputParameters[“Target”];

entity[“attribute”] = value;

3 thoughts on “Plugins recursion – how can you handle it?

  1. Ryan

    Thanks for this post. Currently racking my brain on a deployment that has multiple recursive plugin calls, and trying to follow what happens when a plugin makes one (or more) updateRequests to the target entity, and those requests do the same. Suddenly order of operations isn’t so clear.

    Would be awesome if MSFT spelled out your best practice more clearly “Try not to call service.Update at all” – though they do indicate that changes to the request should be made in the pre-op stage.

    Was considering writing a blog post about this scenario. If I do, I will certainly reference yours.

    Reply
    1. Alex Shlega Post author

      Hey, it helps not to call “updates” from within the plugin. If you can have your code in pre-operation, you can, usually, just set Target attributes directly. Those changes will, then, be applied to the target record without having to do additional “update” calls.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *