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

asynchronous method 'Quartz.Core.QuartzSchedulerThread.Run()', is waiting on a synchronous call to method 'System.Threading.Monitor.Wait(object, int)' #2354

Open
A9G-Data-Droid opened this issue May 6, 2024 · 2 comments · May be fixed by #2373

Comments

@A9G-Data-Droid
Copy link
Contributor

Describe the bug

I have a windows service I wrote in .NET8 that builds Quartz as a hosted service. It works great. It runs things on a schedule. When my service goes to stop it hangs indefinitely, never fully stopping. The final log I see is right before the quartz shutdown line. I have my services ExecuteAsync code wrapped in a try...catch with await _scheduling.Shutdown().ConfigureAwait(false); in the finally to ensure that this is the last thing it does before returning from ExecuteAsync where the host would handle the disposing of Quartz and everything else.

I attached VS2022 debugger to the hung service, exported a dump, and analyzed it in VS2022.

It says AA0001 Thread pool thread or asnchronous task blocked on a synchronous call

1 threads are performing asynchronous work in method 'Quartz.Core.QuartzSchedulerThread.Run()', but are waiting on a synchronous call to method 'System.Threading.Monitor.Wait(object, int)'. This may cause thread pool starvation and hangs.

Potential fix

Do not synchronously wait on Monitors, Events, Tasks, or any other objects that may block your thread. See if you can update the method to be asynchronous.

Version used

Quartz (3.8.1)

To Reproduce

  1. Follow guide to make Windows Service in .NET Core
  2. Follow guide to add Quartz to hosted service
  3. Schedule a job
  4. Start Quartz
  5. Put await _scheduling.Shutdown().ConfigureAwait(false); at the end of your ExecuteAsync method inside your Windows service
  6. Service is now hung and can't exit gracefully.

Expected behavior

.Shutdown should either complete or throw.

Additional context
The debugger help text is fairly clear that there is a problem with the async code pathways. Looking at the code for Quartz.Core.QuartzSchedulerThread.Run I do see the usage of lock and Monitor.Wait(sigLock, timeUntilContinue); which do not follow async programming as they are both synchronous. The new way to await a lock in async code is usually SemaphoreSlim

This issue appears to be the reason that AsyncMonitorwas written.

@lahma
Copy link
Member

lahma commented May 6, 2024

Would you like to submit a PR and propose some improvements?

@A9G-Data-Droid
Copy link
Contributor Author

Sure! I am looking at it now.

A9G-Data-Droid added a commit to A9G-Data-Droid/quartznet that referenced this issue May 9, 2024
 - Avoid blocking synchronously in async methods
 - Ignore new warnings when WONTFIX deferred
 - Don't run async methods synchronously if you can avoid it
 - Convert ValueTask ToTask if you must run synchronously
 - Implement JoinableTask when awaiting from multiple places

quartznet#2354
Possibly related to quartznet#2133
A9G-Data-Droid added a commit to A9G-Data-Droid/quartznet that referenced this issue May 9, 2024
 - Avoid blocking synchronously in async methods
 - Ignore new warnings when WONTFIX deferred
 - Don't run async methods synchronously if you can avoid it
 - Convert ValueTask ToTask if you must run synchronously
 - Implement JoinableTask when awaiting from multiple places

quartznet#2354
Possibly related to quartznet#2133
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 a pull request may close this issue.

2 participants