I think the best way to explain this topic is in “FAQ” format:
1. What is persistence?
Persistence (in this context) means taking a snapshot of the state of a workflow job and storing it in the database. This is similar to clicking the “Save” button when you are writing a Word document. Persistence is a common term in WF (Windows Workflow Foundation) on which CRM workflow is based. The “snapshot” of the workflow job is serialized and stored in the Async Operation table.
2. When are workflows persisted?
CRM will automatically persist workflow jobs right after successfully completing any of these Out-of-the-Box workflow steps:
- Assign Record
- Start Child Workflow
- Create Record
- Send E-mail
- Change Status
- Update Record
Additionally, whenever the workflow goes into a “waiting” status (not due to an error), it will persist to database.
3. In what cases does this matter?
When a workflow is suspended due to a recoverable error, the user is allowed to manually resume the workflow. But when you click “Resume”, from what step is it going to resume? This depends on the last time that the job was persisted. In some cases, you might end up re-executing some steps because your workflow job did not persist after each step. For example, consider this workflow:
1. Create a record (CRM automatically persists after a successful Create step)
2. Custom activity to create the record in an external system
3. Send email to the record owner to notify that the record has been created in CRM and in the external system. (CRM automatically persists after a successful Send E-mail step)
Now imagine that the new record owner did not have a valid email address in CRM. In this case, the job will be suspended and you will need to enter the email address in the user record and then resume the workflow:
Note that the last persistence point is after the create step (because custom activity steps are not persisted). Therefore, when you resume the workflow, it will resume from the beginning of step 2. Thus your workflow will end up executing step 2 twice and you end up with a duplicate in the external system. I hope this example helps illustrate why persistence does matter and can affect the workflow behaviour when resuming suspended jobs.
4. So how can I control persistence?
It is very limited the amount of control you have on persistence. For example, you cannot prevent CRM from automatically persisting the workflow job for the scenarios described above. However, there are some tricks to force CRM to persist the job where it usually wouldn’t. In the example above, I would have liked to persist the workflow job after step2 completed successfully. In order to do that I could have easily used stages so if my custom activity is inside its own Stage then it will be persisted, because CRM will always persist after a stage is successfully completed.
This workaround (using stages) works most of the times, however stage steps cannot be nested and in some scenarios you want to persist a step that is nested inside another one (for example a custom activity inside a condition branch). Unfortunately, there is not much else you can do to force your custom workflow activity to persist the job upon successful completion. Stay tuned for the CRM2011WorkflowUtilities as I will soon provide a “Persist” custom workflow activity which you can use in your workflows.
5. What about the old PersistOnClose attribute?
In WWF3.5 (CRM 4.0) you could add the [PersistOnClose] attribute to your custom workflow activity (System.Workflow.ComponentModel.SequenceActivity) to force CRM to persist when your custom workflow activity is finished executing. For back-wards compatibility, this is still the case in CRM 2011. However, if you build new custom workflow activities for CRM 2011 you should use WF4 (System.Activities.CodeActivity) which does not support the [PersistOnClose] attribute. In short, if you have CRM 4.0 custom workflow activities they will continue to work in CRM 2011 and the [PersistOnClose] functionality will also work, but you should think about upgrading them to WF4.
6. What about the WF4 “Persist” activity (System.Activities.Statements.Persist)
This Out-of-the-box activity that is included in the WF4 activity palette forces the workflow host to persist. Unfortunately, you cannot use this activity in CRM unless you design your workflows in the WF4 designer and upload them as XAML workflows in CRM (which is not supported in CRM Online). Stay tuned for the CRM2011WorkflowUtilities as I will soon provide a similar “Persist” custom workflow activity which you can use in your workflows in the CRM process designer.