I’m probably not the first and only one, and every time I can just kick myself in the face.
Whenever I try to do something like place element or tag element and I left it on automatic execution, it means I lost half an hour of work easy.
Is there any way to un-freeze Dynamo and/or Revit? I feel like there should really be a shortcut to terminate code execution, or a way for Dynamo to handle these issues altogether (like ignoring place element after the first cycle). Is there a fix or workaround planned (other than me not being stupid) to prevent this loss of productivity in the future?
Currently, no. It’s almost a rite of passage at this point. It’s something you just get better at the more you experience it, but I still do it on a regular basis and understand how frustrating it can be.
That being said, it would be nice to have some way of dealing with the situation when it comes up. I don’t know if there’s anything actively being worked on to address this, but it has been requested multiple times and the development team is definitely aware of it.
Keep in mind, if you get a hard crash you should actually be able to pull the backup. Unfortunately, this situation typically ends in an infinite loop (or close to it) so you don’t actually crash. I try to keep all my Revit-side nodes frozen (if possible) during development and only unfreeze for a final, manual run.
Hi @Bram_Weinreder1 - there are a couple of things at play here which I’ll try to shed some light on.
Dynamo works within the idle thread of Revit as an in-process application. What this means is that the entire world (environment) that Revit knows is wrapped up into a single entity, and Dynamo lives inside it. When Revit is not doing anything, it is idling, and Dynamo takes advantage of this process to work within that idle space. This is due to how Revit commits work, called Transactions and why by default you’ll see Dynamo132531543243151 in the Undo stack of Revit after running a a graph.
Other hosts of Dynamo, such as Robot Structural Analysis or FormIt use an out-of-process connection, where their worlds and Dynamo’s are different, and they simply communicate via inter-process communication. You can think of this as sending data to each other, such as strings, or geometry to be serialized (encoded to a simple form with a small footprint) or deserialized (decoded into complex things). When one of these worlds collapses, the other one persists and simply cannot send or receive information until it’s back online.
As Dynamo operates inside the world of Revit, if Dynamo crashes so does Revit, or vice versa. This means there is no way to “exit out of Dynamo” and not have Revit also be exited, as the assemblies and components that are being used are loaded into that space and when you kill some of them, the rug is pulled out from under the others. This has historically been standard, but will be changing with .NET 8 and above, of which we are looking to transition to in conjunction with all our hosts as dynamic loading/unloading on an as-needed basis of these pieces becomes possible. It’s also changing with Revit Design Automation, which are out-of-process API’s for Revit
But so far, they are a subset of functionality and will not allow many actions, especially UI actions (Many of the buttons you click in Revit and things like the dropdown nodes in Dynamo).
This means, unfortunately, that if something goes wrong there is no way to unfreeze Dynamo or Revit
Which is not what you wanted to hear, but in the not-to-distant future there may be (.NET 8)!
With regards to long-running operations and termination of code execution it’s a little tricky as mostly this is a single operation taking a long time (i.e. a node with replication) rather than a sequence of lots of little operations that add up to a larger set. To cancel the code we have to inject a cancel command into that sequence, and if the operation is a long running one it’s mostly redundant. And as we’ve mentioned above, there isn’t a way to cancel it out and not kill both Revit and Dynamo at the same time either. This is the reason that there is no Cancel button inside DynamoRevit as it wouldn’t actually function how users want it to.
That being said, Infinite Loops inside of DynamoRevit are indeed a problem and we could do better here with some safeguarding. The broader community has largely worked around this issue by using Manual mode rather than Automatic.
I actually have a ‘recovery’ process of sorts.
If you check your dynamo backup folder location (usually something like %AppData%\Dynamo\Dynamo Revit\backup) you can get the most recent backup.
Wait a few minutes for the backup to trigger (I think it defaults to 5 minutes, which I’d spend trying to grab the run mode to switch it off automatic onto manual to end the loop) to confirm the backup is working. Once you’ve seen the file update, force quit Revit.
From there you can change the name of the backup (appending .recover.dyn is a personal preference), and copy it to your working directory.
When you restart Dynamo, open the renamed copy of the backup instead of the original, and all work (excepting edits inside a python node) should be there.
Thank you for this insight.
I have written a fair share of Revit addins, so I know how hard it can be to just cancel a running transaction. The code has to reach a point first where it can handle user input.
As a workaround though, I want to see if I can insert a bool that can be set from any point in the script. Certain nodes will only be executed if the the boolean is set to true, and a condition after that node (let’s say list size > 1) will set it to false again, so that it will only be executed once until I reset the bool. Would something like this work? If it does, I might wrap this behavior around the [place element] in a custom node for repeat use.
That would be the best way to go about it. And honestly, while the automatic execution is nice, I think it doesn’t represent the use state for the majority of the less code-savvy coworkers who just run it through Dynamo Player which is built in revit.
Yes, you can force a null output on second run in a few ways. One tool I built write the new element IDs to an external file with the file name matching the name of graph + the name of the model. If the file was not found it would run the bulk of the code, but if the file was found it would open up and attempt to get the new Revit elements out of the DB to confirm everything was still good; effectively it was a ‘cross session trace’ mechanism for a non-element binding situation. Not a perfect fit for what you’re after but was ideal for my situation which involved a team manually processing corrupted RVTs.
That said, systems like that are tough to build, apt to break, and cumbersome to work with.
Instead it’d likely be more productive to place a node or build a view extension which pops up a message along the lines of “You’re in automatic run mode, and the this may cause infinite loops which can result in data loss” any time you put a potential loop creating node on canvas (ie: all elements of… and a node which creates a new element in the DB),
introduction of a ‘semi auto’ run mode which only triggers when a new node or wire is added to the canvas (thereby preventing infinite loops but keeping most of the value of automatic) would be nice; both of those are events which can be traced and utilized to trigger new events if I’m not mistaken.