Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@mtaku3
Copy link
Collaborator

@mtaku3 mtaku3 commented Jan 25, 2023

Some part of code uses Task.Wait() or Task.Result. But these occurs deadlock when running on Desktop application or ASP.NET Web Application, which its main thread is limited to single concurrency.
To avoid that, I used Task.Run(async () => await AsyncMethod()).GetAwaiter().GetResult().
Task.Run() will execute inner async method on other thread (threadpool by default) so that deadlock will be occured in lower chance.
Task.GetAwaiter().GetResult() gets the result without forgetting exceptions.
Task.Wait() or Task.Result are fire-and-forget, which forgets exceptions raised inside of async method. To re-throw the exceptions, use Task.GetAwaiter().GetResult().
I tried my best to choose the best workaround to avoid deadlock. AFAIK, this is the best way to do that.
But still, there's potential risk of deadlock. (i.e. when ThreadPool hits to its concurrency limit)
So I strongly recommend to notice users about this so that users don't have to spend extra time to find out the deadlock issue.

@mtaku3 mtaku3 marked this pull request as ready for review January 25, 2023 08:49
@iluvadev
Copy link
Owner

iluvadev commented Jan 31, 2023

I apologize for not replying sooner - I've been a little busy and you're bringing up an issue I'm not familiar with. It seems important enough to spend a good amount of time on, and what you've done makes perfect sense.
I will try to review the PR in a few hours.

And... You are all right, I abused the Result property without considering deadlocks in some environments.

Thanks!! Again :)

@iluvadev iluvadev added the good first issue Good for newcomers label Jan 31, 2023
@mtaku3
Copy link
Collaborator Author

mtaku3 commented Jan 31, 2023

No problem. Please take your time 😀
I'm happy to contribute to this project ❤️

@iluvadev
Copy link
Owner

iluvadev commented Feb 1, 2023

I've been reading about the await deadlock problem and I think the best solution would be to minimize the methods that convert from async to sync: modifying the public API, expose almost only async methods and removing unnecessary async to sync methods.
I really like your approach and it could be used in those methods that necessarily have to do the async-sync conversion

Warning: this commit breaks some compatibility with previous versions:

In Collections, these methods are removed:
- `SaveChanges` -> Use `SaveChangesAsync` instead
- `Save` -> Use `SaveAsync` instead
- `Remove(string? id) -> Use `RemoveAsync(string? id)` instead
- `Delete(string? id) -> Use `DeleteAsync(string? id)` instead
- `GetId` -> Use `GetIdAsync` instead
- `Contains` -> Use `ContainsAsync` instead

In every Item mapped from PocketBase, these methods are removed:
- `Reload` -> Use `ReloadAsync` instead
- `Save` -> Use `SaveAsync` instead

In DataService, these methods are removed:
- `GetById<T>` -> Use `GetIdAsync<T>` instead
- `SaveChanges` -> Use `SaveChangesAsync` instead
@iluvadev
Copy link
Owner

iluvadev commented Feb 4, 2023

I made several modifications to minimize the async to sync conversion, some of these breaks compatibility with older versions.

In Collections, these methods are removed:

  • SaveChanges -> Use SaveChangesAsync instead
  • Save -> Use SaveAsync instead
  • Remove(string? id) -> Use RemoveAsync(string? id) instead
  • Delete(string? id) -> Use DeleteAsync(string? id) instead
  • GetId -> Use GetIdAsync instead
  • Contains -> Use ContainsAsync instead

In every Item mapped from PocketBase, these methods are removed:

  • Reload -> Use ReloadAsync instead
  • Save -> Use SaveAsync instead

In DataService, these methods are removed:

  • GetById<T> -> Use GetByIdAsync<T> instead
  • SaveChanges -> Use SaveChangesAsync instead

But there are still some async to sync conversions that use your hack, but to really avoid the async deadlock more work is needed. The cases are:

  1. When iterates over a Collection (or filtered collection), and the next item is not downloaded from PocketBase
  2. When tryies to get a property value of an item that is not downloaded from PocketBase yet

I think that a solution could be making a real sync version of these methods, and maybe creating async alternatives

Again, thank you so much 👍🏼

@iluvadev iluvadev merged commit 66c7fc2 into iluvadev:main Feb 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants