Search code examples
autodesk-forgeautodesk-designautomation

Forge Work Item Timeouts for Design Automation API


My company currently uses Autodesk Forge to read data from AutoCAD DWG files using the Design Automation API. However somewhat frequently, our work items will fail (especially on larger DWG files), and the returned report mentions the below error:

Error: AutoCAD Core Console is shut down due to timeout.

After reading online, I found this other Stack Overflow post with the same issue, where a comment mentions that the Design Automation will consider the task hung if no outputs have been written for 60 seconds. So, I tried adding a Console.WriteLine() (I'm using C#) every time we read an entity from the CAD file (which happens far more frequently than every 60 seconds), but the same timeout issue still persists. I'm suspecting the "console" might need to be written to differently within the AutoCAD engine, but I'm unsure how.

Does anyone know how we can make a work item last longer than 60 seconds? This is particularly important since many of our customers have large (think >100 MB) DWG files that cannot be parsed via our code in under 60 seconds. We have tried parallelizing the work across different work items which has certainly helped and allowed us to handle many of these larger files, but we still would like a way to have a longer-lasting work item in the occasional scenario where a file needs that.

Thanks!

P.S. I also tried the HeartBeat class here, which unfortunately also didn't stop the timeouts.


Solution

  • After talking with Autodesk support (Madhukar from Autodesk was helpful), it looks like the only way to log a heart beat that becomes visible to Forge is to use Editor.WriteMessage().

    To summarize Madhukar's explanation, AutoCAD is special compared to Revit and Inventor in that it has its own console environment AcCoreConsole.exe. This intercepts regular writes to stdout (e.g. Console.Write()) and instead directs Editor.WriteMessage()/acutPrintf to stdout instead. This is done because many of the underlying components AutoCAD uses (e.g. ASM) writes garbage debug messages to stdout, which Autodesk didn't want to surface to the user. So, normal Console.Write() calls will never get propagated and seen by Forge.

    As a result, use Editor.WriteMessage() at a frequency greater than every 1 minute in order to stay under the 1 minute heart beat timeout interval.

    NOTE 1: Background threads don't work when running the AutoCAD Forge work items. Also paraphrasing Madhukar's explanation, SynchronizationContext only works when the host application has a "message pump", which is not available when running the AcCoreConsole CLI (but is available in acad.exe, which is perhaps why such marshalling of AutoCAD API calls from background threads to the UI threads works for plugins run from the AutoCAD application, e.g. as explained in this blog post). So, heart beats must be logged from the main thread for the AutoCAD engine.

    NOTE 2: One gotcha: you must use a NEW-LINE TERMINATOR in the string you pass to Editor.WriteMessage(). I don't know exactly why, but without a new-line none of the messages actually get written and the work item will timeout. Forge work items will have an associated report (and the work item should include the download url for the report) -> you can confirm that you are in fact writing a heart beat that is visible to Forge if you can see your heart beat logs in the report.

    Below is an example command that takes two minutes and successfully runs in Forge:

    [CommandMethod("ExampleTimeout")]
    static public void Print()
    {
        var doc = Application.DocumentManager.MdiActiveDocument;
        var ed = doc.Editor;
        for (int timeWaited = 0; timeWaited < 120; ++timeWaited)
        {
            // Write heart beat to the AutoCAD editor, NOT the Console.
            // Also, add a new-line character for message to be written!
            ed.WriteMessage("Heart beat!\n");
            // Sleep for one second each iteration
            Thread.Sleep(1000);
        }
        ed.PostCommandPrompt();
    }
    

    NOTE 3: One last gotcha -> after adding the heart beat and being able to run work items longer than 1 minute, you will likely need to increase the time set by the limitProcessingTimeSec attribute for the engine you're using for the Design Automation API. See the default and max limits here. Work items default to 100 seconds, but you can set them to run up to 15 minutes. This can be done by setting the backend service limits via the HTTP request described here.