TuesPechkin
TuesPechkin copied to clipboard
Rendering large files concurently
I'm getting some errors when trying to render some large PDFs, especially when trying to do so concurrently.
Here is my singleton:
public static class HtmlToPdfConverter
{
// Singleton so that all users, all threads will share the same converter
public static readonly IConverter Win32Converter =
new ThreadSafeConverter(
new RemotingToolset<PdfToolset>(
new Win32EmbeddedDeployment(
new TempFolderDeployment())));
}
And my MVC method:
public ActionResult Print()
{
var document = new HtmlToPdfDocument
{
GlobalSettings =
{
ProduceOutline = true,
DocumentTitle = "Pretty Websites",
PaperSize = PaperKind.A4, // Implicit conversion to PechkinPaperSize
Margins =
{
All = 1.375,
Unit = Unit.Centimeters
}
},
Objects = {
new ObjectSettings { PageUrl = "en.wikipedia.org/wiki/Roman_Empire" },
new ObjectSettings { HtmlText = "<style>h1 {font-family:Arial}</style><h1>Pretty Websites</h1><p>This might take a bit to convert!</p>" },
new ObjectSettings { PageUrl = "www.google.com" },
new ObjectSettings { PageUrl = "www.microsoft.com" },
new ObjectSettings { PageUrl = "www.github.com" }
}
};
byte[] result = HtmlToPdfConverter.Win32Converter.Convert(document);
return new FileContentResult(result, "application/pdf");
}
Note the large Wikipedia article. If I hit this application to render several PDFs at the same time (or sometimes just one at a time), I have run into two errors.
Error 1:
An exception of type 'System.AccessViolationException' occurred in TuesPechkin.dll but was not handled in user code
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source Error:
Line 57: }; Line 58: Line 59: byte[] result = HtmlToPdfConverter.Win32Converter.Convert(document); Line 60: Line 61: return new FileContentResult(result, "application/pdf");
Source File: c:\Projects\HtmlToPdf\HtmlToPdf\Controllers\HomeController.cs Line: 59
Stack Trace: [AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.] TuesPechkin.ThreadSafeConverter.Invoke(FuncShim`1 delegate) +286 TuesPechkin.ThreadSafeConverter.Convert(IDocument document) +138 HtmlToPdf.Controllers.HomeController.Print() in c:\Projects\HtmlToPdf\HtmlToPdf\Controllers\HomeController.cs:59 lambda_method(Closure , ControllerBase , Object[] ) +101 System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +59 ...
Error 2a:
Managed Debugging Assistant 'CallbackOnCollectedDelegate' has detected a problem in 'C:\Program Files (x86)\IIS Express\iisexpress.exe'.
Additional information: A callback was made on a garbage collected delegate of type 'TuesPechkin!TuesPechkin.StringCallback::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.
Error 2b:
An exception of type 'System.NullReferenceException' occurred in TuesPechkin.dll but was not handled in user code
Additional information: Object reference not set to an instance of an object.
Source Error:
Line 57: }; Line 58: Line 59: byte[] result = HtmlToPdfConverter.Win32Converter.Convert(document); Line 60: Line 61: return new FileContentResult(result, "application/pdf");
Source File: c:\Projects\HtmlToPdf\HtmlToPdf\Controllers\HomeController.cs Line: 59
Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.] TuesPechkin.ThreadSafeConverter.Invoke(FuncShim`1 delegate) +286 TuesPechkin.ThreadSafeConverter.Convert(IDocument document) +138 HtmlToPdf.Controllers.HomeController.Print() in c:\Projects\HtmlToPdf\HtmlToPdf\Controllers\HomeController.cs:59 lambda_method(Closure , ControllerBase , Object[] ) +101 System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +59 ...
While I am determined to get to the bottom of the errors and correct them (for one, I really need to see about preserving the stack trace that occurs inside of the synchronized thread) I do have to take the time to mention that if you have really long conversions to run like this, you're probably better off using messaging and a pool of worker services to handle your conversions. Check out Rebus, MassTransit, Rhino Service Bus, or NServiceBus (commercial.)
Do you have any timing or statistics on how long the conversion takes before it blows up? How many conversions process successfully? What is your request timeout set to, or is your compilation mode set to debug when you run your test?
I tried the code above and got the same error. I tweaked the way the singleton was getting created and this fixed the issue:
public static class HtmlToPdfConverter
{
/// <summary>
/// Allocate ourselves.
/// We have a private constructor, so no one else can.
/// </summary>
private static readonly IConverter _instance = new ThreadSafeConverter(
new RemotingToolset<PdfToolset>(
new Win32EmbeddedDeployment(
new TempFolderDeployment())));
/// <summary>
/// Access SiteStructure.Instance to get the singleton object.
/// Then call methods on that instance.
/// </summary>
public static IConverter Converter
{
get { return _instance; }
}
}
brendan-rice, I tried your fix when I was getting Error 2a/2b... instead of getting it 100% of the time in a certain test case scenario, I'm getting it about 50% of the time now.
//before
//private static IConverter _converter = null;
//private static IConverter Converter
//{
// get
// {
// if (_converter == null)
// _converter = new ThreadSafeConverter(new RemotingToolset<PdfToolset>(new Win32EmbeddedDeployment(new TempFolderDeployment())));
// return _converter;
// }
//}
//after
private static readonly IConverter _instance = new ThreadSafeConverter(new RemotingToolset<PdfToolset>(new Win32EmbeddedDeployment(new TempFolderDeployment())));
public static IConverter Converter
{
get { return _instance; }
}
These are 1-3 page PDFs, so not really "big" ones. As far as I know we only get this error in debug mode but we haven't begun formal testing on our test server yet.
I'm chiming in again to say that disabling the stupid Browser Link setting in Visual Studio (2013) seems to have fixed the error. I'll come back to this thread if we ever get that error again.
http://www.poconosystems.com/software-development/how-to-disable-browser-link-in-visual-studio-2013/
Could you please, paste the whole singleton class?
Thank you very much
Hello everyone,
Could you help me, please? I'm getting a similar error:
Message: Managed Debugging Assistant 'CallbackOnCollectedDelegate' has detected a problem in 'D:\Dev\1.0.0.0\URLConverter\bin\Release\URLConverter.vshost.exe'.
Additional information: A callback was made on a garbage collected delegate of type 'TuesPechkin!TuesPechkin.StringCallback::Invoke'.
Does anyone know how to fix it?
Thank you