The following are tips for testing Windows Workflow Foundation instances that contain delay activities (timers) when used in conjunction with a passivation store.  This list of tips is certainly not exhaustive, but I believe that I’ve accumulated enough useful techniques to warrant sharing with others.

1.       Purge all rows from your InstanceState table that may contain passivated workflows of the type you’re testing.

2.       In order to support your ability to conveniently blow away InstanceState rows, each developer should have his or her own private persistence database. If possible, avoid using a shared database for this type of testing.

3.       For testing (and perhaps even production) consider merging your passivation store with your application database to help facilitate referential integrity. You will undoubtedly have an associative table to map workflow instance ID’s against your application’s key field(s). This is not Microsoft’s recommended production deployment strategy, but it is a useful configuration to utilize during development and debugging.

4.       It’s impractical to test timers with intervals that are set to days, weeks or months—so allow the ability in your application design to modify these intervals in a data driven fashion.

5.       Don’t test with time intervals that are too small. The default poling interval for determining expired timers in need of service is 2 minutes. See #10 below to adjust. 

6.       Don’t bump the poling interval for expired workflows down too low as you can create scenarios where you are poling faster than you are processing workflows or where you don’t have enough time to operate the debugger before the next timer cycle begins.

7.       Be aware of the multi-threaded nature of the code you are working with. Timers will cause passivated workflows to rehydrate and begin execution upon timer expiration while you may be busy debugging other workflow instances. If you haven’t removed rows from your InstanceState table you may find yourself simultaneously debugging multiple workflow instances—which is okay if that was your intention, but it generally is not.

8.       Add this.WorkflowInstanceId to your diagnostic output (Trace.WriteLine and friends) so that you’re aware of which workflow instance is responsible for the diagnostic output being generated. When multiple workflows begin executing at once, you’ll be glad you have this. You may also consider adding the managed thread id as well.

9.       If you’re workflow operates on a shared resource, use a SychronizedScope container activity to protect access to it. This is true even for workflows that do not use delay activities, but it is mentioned here for completeness.

10.   You can adjust the timer poling interval using the LoadIntervalSeconds attribute of the System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService configuration entry.