TuesPechkin icon indicating copy to clipboard operation
TuesPechkin copied to clipboard

Rendering large files concurently

Open fosterwork opened this issue 10 years ago • 7 comments

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 ...

fosterwork avatar Jan 23 '15 23:01 fosterwork

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.)

tuespetre avatar Jan 24 '15 04:01 tuespetre

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?

tuespetre avatar Jan 24 '15 04:01 tuespetre

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 avatar Feb 26 '15 14:02 brendan-rice

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.

cvillhauer avatar Mar 30 '15 19:03 cvillhauer

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/

cvillhauer avatar Mar 30 '15 22:03 cvillhauer

Could you please, paste the whole singleton class?

Thank you very much

julitillo avatar Apr 08 '15 09:04 julitillo

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

germanpeart avatar Apr 09 '15 22:04 germanpeart