Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crash report fixes #15147

Merged
merged 20 commits into from
Apr 29, 2024
Merged

crash report fixes #15147

merged 20 commits into from
Apr 29, 2024

Conversation

pinzart90
Copy link
Contributor

@pinzart90 pinzart90 commented Apr 17, 2024

DYN-4849 - Handle exceptions coming from 3d party packages.

Fix sender object on Crash handlers
Only handle exceptions coming from assemblies that were loaded from a 3rd party package
Skip crash window and rethrow exceptions during tests
Removed feature flag for CER (will always be on)

Copy link

github-actions bot commented Apr 17, 2024

UI Smoke Tests

Test: success. 2 passed, 0 failed.
TestComplete Test Result
Workflow Run: UI Smoke Tests
Check: UI Smoke Tests - net8.0

@@ -839,6 +839,18 @@ private void CrashGracefully(Exception ex, bool fatal = false)
{
try
{
if (!fatal)
{
var localPkg = Model.GetPackageManagerExtension()?.PackageLoader?.LocalPackages?.FirstOrDefault(p => p.LoadedAssemblies.FirstOrDefault(a => a.Name == ex.Source) != null);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might happen that one of these package assemblies is already loaded by dynamo (as a dependency), so we could potentially continue running even though the exception is coming from somewhere else. (not the pacakge we identified)
But I think that might be an edge case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment this code will always continue the session and only log the exception.
As an alternative, we could show a warning message that exception ex was thrown from package X and give the user a choice to continue the dynamo seasion or crash and send CER report
@Amoursol any preferences?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the source property is not set explicitly, the runtime automatically sets it to the name of the assembly in which the exception originated.

hmm, so in most cases this will work.

Have you verified that this property is set to the short name or full name of the assembly? Does it include the version number and culture?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about the edge case where a user has shipped system binaries (Microsoft) or Dynamo binaries?

Copy link
Member

@mjkkirschner mjkkirschner Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about also logging something to ADP so we have analytics on how often these crashes occur without actually crashing?
whoops missed your call to track!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you verified that this property is set to the short name or full name of the assembly
It is just the short name. Obviously this can be overridden by custom exceptions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about the edge case where a user has shipped system binaries (Microsoft) or Dynamo binaries?
Not sure at the moment how I can identify these sort of cases...Are the package LoadedAssemblies actually loaded or they can just be on disk without actually being the ones to be loaded...I can check this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, LoadedAssemblies could be already loaded assemblies. So if a user supplies a dotnet system dll, then all the exceptions from that dll (even if it was loaded by dotnet previously) will not cause a hard crash anymore.

I can verify if the assemblies have been loaded already, probably at a small performance penalty

Copy link
Contributor

@aparajit-pratap aparajit-pratap Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: does it still make sense to have this check (code path) in the same function (CrashGracefully), as it isn't crashing in this case?

Copy link
Contributor Author

@pinzart90 pinzart90 Apr 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CrashGracefully is called from multiple places.
Another way I could go is to not subscribe to the unhandled_exception_handlers at all during testing. But I think the logging is still valuable for debugging. So I suggest we leave the rethrow in the CrashGracefully method for now

@pinzart90
Copy link
Contributor Author

@QilongTang QilongTang added this to the 3.2 milestone Apr 18, 2024
{
DynamoViewModel dynamoViewModel = sender as DynamoViewModel;
Copy link
Member

@mjkkirschner mjkkirschner Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit pick - use var
also pattern match is would be nice with an if statement for the second line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean like so ?

            DynamoModel model = null;
            var dynamoViewModel = sender as DynamoViewModel;
            if (dynamoViewModel != null)
            {
                model = dynamoViewModel.Model;
            }
            else if (sender is DynamoModel dm)
            {
                model = dm;
            }

@mjkkirschner
Copy link
Member

can you add a test for this by raising a mocked exception and setting source explicitly to the name of an assembly in one of the packages we load by default during tests?

@pinzart90
Copy link
Contributor Author

can you add a test for this by raising a mocked exception and setting source explicitly to the name of an assembly in one of the packages we load by default during tests?

Sure can. Totally forgot about tests..

Copy link
Contributor

@aparajit-pratap aparajit-pratap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give some context to why was the crash happening in the first place?

@pinzart90
Copy link
Contributor Author

Can you give some context to why was the crash happening in the first place?

The exception is thrown somewhere in the juggnernaut assemblies. Not sure what.
The request was to dismiss/ignore exceptions (if possible) that are coming from 3d party package assemblies. Basically don't crash dynamo if a pacackage does not work properly

@aparajit-pratap
Copy link
Contributor

Can you give some context to why was the crash happening in the first place?

Is the crash because an assembly that's already loaded is trying to be loaded again because it's a dependency of a package?

@pinzart90
Copy link
Contributor Author

because an assembly that's already loaded is trying to be loaded again because it's a dependency of a

No, it is just a null reference exceptions or something similar

List<string> appDomainAssemblies = null;
var binFiles = new DirectoryInfo(BinaryDirectory).EnumerateFiles("*.dll");
if (binFiles.Any()) {
appDomainAssemblies = AppDomain.CurrentDomain.GetAssemblies().Select(x => x.GetName().Name).ToList();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hopefully not too much of a performance hit here.
This will run for every loaded pkg that has at least one binary on disk.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I try to move this a level up, the assembly list might change (because we iterate all the types and dependencies might get loaded)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you considered how ALCs and packages containing extensions or binaries in other folders might affect this check?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I am still curious about the name property of the assembly, does that contain the version number or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not consider those. THanks !
binaries in other folders might affect this check? - CHanged the code to check if the faulty assembly is inside the package root folder.
ALCs - Changed the code to use TargetSite.Module.Assembly - Gets the method(and assembly) where the exception was thrown - https://learn.microsoft.com/en-us/dotnet/api/system.exception.targetsite?view=net-8.0 (not sure why I did not see this before)
curious about the name property of the assembly - I am now using the equality operator on assemblies which should consider version and culture and ALCs

if (DynamoModel.IsTestMode)
{
// Do not handle the exception in test mode.
// Let the test host handle it.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might have covered this at standup but can you remind me again what you see in tests if the exception is marked as handled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If (during tests) the exception is marked as handled inside the ex_handler, then the test that threw the exception might pass (as if nothing was thrown)
Our tests have a single entry point for async tasks (we run these with DispatcherUtil.DoLoop). Whenever an async task throws an exception (and if unhandled) it will propagate until the DIspatcherUtil.DoLoop calls and eventually be caught by the nunit test runner

@aparajit-pratap
Copy link
Contributor

@pinzart90 your new test is failing. Can you check? You might already be on top of it but I'm monitoring the builds this week ;)

@pinzart90 pinzart90 merged commit 59e22d8 into master Apr 29, 2024
23 checks passed
@pinzart90 pinzart90 deleted the crash_report_fixes branch April 29, 2024 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants