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

Using a transaction in a session makes unity editor non responsive when attempting to start next session #783

Closed
christianmrswordsmith opened this issue Sep 18, 2020 · 12 comments
Assignees

Comments

@christianmrswordsmith
Copy link

[REQUIRED] Please fill in the following fields:

  • Unity editor version: 2019.4.9f1
  • Firebase Unity SDK version: 6.15.2
  • Source you installed the SDK: Unity Package Manager (.unitypackage or Unity Package Manager)
  • Problematic Firebase Component: Cloud Firestore for Firebase (Auth, Database, etc.)
  • Other Firebase Components in use: ____ (Auth, Database, etc.)
  • Additional SDKs you are using: _____ (Facebook, AdMob, etc.)
  • Platform you are using the Unity editor on: Windows 10 (Mac, Windows, or Linux)
  • Platform you are targeting: iOS, Android (iOS, Android, and/or desktop)
  • Scripting Runtime: IL2CPP (Mono, and/or IL2CPP)

[REQUIRED] Please describe the issue here:

Unity Editor becomes non responsive on play if a Firestore transaction was made in the previous session.

Steps to reproduce:

Have you been able to reproduce this issue with just the Firebase Unity quickstarts (this GitHub project)?
Haven't tried yet.

What's the issue repro rate? (eg 100%, 1/5 etc)
100%

What happened? How can we make the problem occur?
Editor becomes non responsive.
Press play
Run code that makes a transaction
Press stop

Press play
Unity editor is now stuck

Relevant Code:

DocumentReference accountDocumentRef =
				_firestoreClient.Db.Document(_documentPath);

			DocumentReference profileStateDocRef =
				_firestoreClient.Db.Document(
					$"{_profileStatesCollection}/{_userId}_{profileStateId}");

			bool transactionResult = await _firestoreClient.Db.RunTransactionAsync(async transaction =>
			{
				DocumentSnapshot snapshot = await transaction.GetSnapshotAsync(accountDocumentRef);
				AccountDocument accountDocument = snapshot.ConvertTo<AccountDocument>();

				if (accountDocument.ProfileMeta.ContainsKey(slotId.ToString())) return false;

				accountDocument.ProfileMeta.Add(slotId.ToString(),
					new ProfileStateMetaData(profileStateId, childName, ProfileStateDocument.kCurrentVersion,
						_profileStatesCollection));
				transaction.Set(accountDocumentRef, accountDocument);
				transaction.Set(profileStateDocRef, profileState);

				return true;


			});
			_accountData = await GetAccountData();
			if (!transactionResult) return null;
			return await GetProfileStateController(profileStateId);*/
@patm1987
Copy link

Given the nature of this issue, I wouldn't be surprised to see this occurring. On a quick inspection, I can't easily reproduce this.

I modified the test app like this:

    private IEnumerator WriteDoc(DocumentReference doc, IDictionary<string, object> data)
    {
      var setTask = FirebaseFirestore.DefaultInstance.RunTransactionAsync(async transaction =>
      {
        transaction.Set(doc, data);
        return true;
      });
      // Task setTask = doc.SetAsync(data);

and tried to capture the issue by rapidly pressing cmd+p after clicking the write doc button.

Since you report this as a 100% repro, if you could get us a good patch for the testapp that gives equivalent reproduction rate - we'll be able to quickly triage this and start looking at a fix (just reply in here with some code to update quickly).

@patm1987 patm1987 added needs-info Need information for the developer and removed needs-attention Need Googler's attention labels Sep 22, 2020
@dconeybe
Copy link

I've actually been actively investigating this issue today and yesterday. It may or may not be related to #757, which is the issue I was trying to investigate. In any case, I'll take ownership of this ticket since there is definitely a bug. My hypothesis at the moment is that the shutdown logic for FirebaseFirestore is freeing a C++ object that is being used in the transaction callback. I'll update this issue when I have some concrete findings.

@dconeybe dconeybe self-assigned this Sep 23, 2020
@christianmrswordsmith
Copy link
Author

Do you guys need a repro project or were you able to reproduce it your self?

@google-oss-bot google-oss-bot added needs-attention Need Googler's attention and removed needs-info Need information for the developer labels Sep 23, 2020
@dconeybe
Copy link

I am able to reproduce so no repro project is needed. However, could you post (e.g. as a gist or attachment) the Unity Editor logs after the crash? That way I can confirm that it is the same crash that I'm investigating. On MacOS, the logs can be found at ~/Library/Logs/Unity/Editor.log.

@dconeybe dconeybe removed the needs-attention Need Googler's attention label Sep 23, 2020
@dconeybe
Copy link

Update: I'm fairly certain that I found the root cause; however, I'm not sure how to fix it. Basically, a ThreadAbortException is propagating from C# into C++.

When the "stop" button is pressed it causes the thread executing the transaction to throw a ThreadAbortException. Normally, we could just wrap the code in question in a try/catch block and suppress the exception, preventing it from leaking into the C++ code from which we were invoked. The problem is that ThreadAbortException is "special", in that it can be caught, but it will automatically be raised again at the end of the catch block. This automatic re-throwing precludes us from suppressing and thus allowing it to leak back into C++ which causes the crash. Thread.ResetAbort() is documented to stop the ThreadAbortException from propagating, but in my testing it had no effects and did not fix the crash.

I'm continuing to investigate but I have no solution nor a workaround at this point.

https://docs.microsoft.com/en-us/dotnet/api/system.threading.threadabortexception

@dconeybe
Copy link

Also, with this new information I'm 99% sure that this issue has a different root cause than #757 (contrary to what I had previously hypothesized).

@dconeybe
Copy link

Update: The hypothesis that ThreadAbortException is causing the crash turned out to be correct, and the root cause was not related to #757. I have implemented a fix for this issue and it is in code review. The fix should be included in the next release but I cannot make any commitments as to the date of that release. For now, the only workaround I can think of is to wait for all transactions to complete prior to restarting your app in the Unity Editor. I realize that this is suboptimal, possibly even impossible depending on how your app is implemented, and I sincerely apologize for the inconvenience.

@dconeybe
Copy link

Update: I don't have much of an update but wanted to reassure anyone watching this issue that a fix is coming and is in the final stages of code review. It's been an incredibly complex fix, far beyond the scope of what I had originally envisioned. The workaround of avoiding re-starting your app in the Unity Editor while one or more transactions are in progress is still valid.

@christianmrswordsmith
Copy link
Author

christianmrswordsmith commented Nov 12, 2020 via email

@dconeybe
Copy link

Yes, that is a known issue as well for which I am also working on a fix. The canonical ticket for it, with a documented workaround, is #845.

@dconeybe
Copy link

Update: The fix for this issue has been submitted (cl/342923297 for Googlers). It should be included in the next release of the Unity SDK. Since there is no further work to do from our end I'm going to close this ticket; however, if this issue persists after the next release please feel free to re-open this issue. In the meantime, the workaround of avoiding re-starting your app in the Unity Editor while one or more transactions are in progress is still valid.

@dconeybe
Copy link

dconeybe commented Dec 3, 2020

FYI The Firebase Unity SDK v7.0.0 was just released and contains the fix for this issue.

@firebase firebase locked and limited conversation to collaborators Dec 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
5 participants