Another post from our ‘customer support archives’. We’ll call this one ‘The case where code executed by workflows behaves differently from code executed by Application pages and why it actually was our own fault’.
We were contacted by a SharePoint developer who is using our PDF Converter to convert files to PDF format from a SharePoint Designer workflow, a common requirement. This developer clearly knew what they were doing and decided to test the system under stress by activating the workflow on a number of files simultaneously, which resulted in a number of horrible SharePoint errors in the Event log, most notably the following ones:
and the SharePoint trace log (in verbose mode) showed the following, all too familiar, messages
Anyone who has done any SharePoint development, including us, will immediately draw the conclusion that somewhere we are not disposing an SPWeb or SPSite object and if it wasn’t for the following we would agree.
When invoking exactly the same code through a SharePoint Application Page, which is how our end-user - non workflow - interface works, everything works great. No errors, no warnings and no memory leaks.
As part of our development process we thoroughly check our code for typical SharePoint dispose leaks using SPDisposeCheck. The PDF Converter comes out completely clean.
When using an out-of-the-box Workflow Activity such as Copy List Item, you get the same ‘errors’ in the SharePoint trace log.
A Google search for DISP_E_EXCEPTION SharePoint returns 1420 results, all from people tearing their hair out in despair. This problem appears to have many different causes and few common solutions.
So, with a nice problem that only occurs under stress at hand we fired up our debuggers. Naturally it all works great when stepping through the code. We tried all kinds of common temporary workarounds such as a big mutex around the entire Workflow Activity, a couple of Sleeps in the code to let the system ‘recover’ and even acts of desperation such as manually calling the Garbage Collector (!)….. nada.
After stripping the code down to its bare minimum, removing all calls to anything remotely complex such as the actual PDF Conversion, we noticed that we were not disposing the stream that comes of our SPFile Object. After adding a Dispose() for that stream all problems went away.
Why this is only a problem when invoked via workflows and why this has not turned up during our own stress tests is anyone's guess. We just hope that this solution will help anyone else with the same problem.
On a separate note, I would really like to thank our customers. They are extremely cooperative when it comes to troubleshooting these kinds of errors. They happily send log files, install interim versions while staying friendly and helpful. Thanks for making our lives a lot easier.