Add BukkitScheduler#createAsyncExecutor API#4064
Conversation
dfee1f9 to
8971625
Compare
Proximyst
left a comment
There was a problem hiding this comment.
Some paper comments missing, otherwise LGTM.
8971625 to
deda936
Compare
cdf6936 to
326eb91
Compare
aikar
left a comment
There was a problem hiding this comment.
the scheduler needs to keep track of these when created, and when a plugin is disabled, shut down the executor so that tasks may flush and try to gracefully shutdown and pause the disable event.
But it should use same timeout that current async tasks do where it gives them time to stop but gives up and will shutdown anyways if not.
.shutdown() should be called before the current async tasks waiting code, and the "wait for executors" should factor in all time spent async tasks (ie if we give 30s and async tasks used 20s of it, don't blindly wait for another 30s, it should be 30s total for both combined)
30s is off memory on what it actually is, and is purely for example purposes.
just this waiting shouldn't add any additional time.
|
I took a slightly different approach which preserves the existing behaviour (present in normal async tasks) of allowing, but strongly warning against, incomplete tasks on reload and shutdown. This I found was slightly easier to implement than calling shutdown(), getting the incomplete tasks, and having to recreate the ExecutorService over reloads. |
* Adds the ability to create an Executor using the BukkitScheduler's cached thread pool which is not coupled to the main thread heartbeat. * Tracks Runnables from PluginExecutors to ensure clean reload and shutdown
bd01075 to
46c016a
Compare
|
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
|
Not stale, don't close. This PR is ready for review in terms of code changes. I will rebase it when I get the chance. |
|
Closing PR, as it seems that this has gone inactive. Seems like you did comment that you'll rebase it whenever so feel free to rebase and leave a comment and we can reopen it for you. 😄 |
Currently, the CraftScheduler will commence asynchronous tasks every tick, per
CraftAsyncScheduler#mainThreadHeartbeat. However, if the main thread is blocked, async tasks will not begin.A common use case involves awaiting the result of an asynchronous computation on the main thread. Using the current API in the BukkitScheduler, this might cause a deadlock, since initiation of async tasks requires the main thread to keep beating.
To solve this, I added the
BukkitScheduler#createAsyncExecutorAPI. This method returns anExecutornot coupled to the server tick loop. If the main thread is blocked, it will still be able to submit tasks, using the server's cached thread pool.Why not tell people experiencing this issue to create their own ExecutorService?
That's completely possible, and I do not want to say it is a bad idea. For many cases, an own thread pool would be preferable. However, doing so negates the advantage of the scheduler's common thread pool, which reuses Craft Scheduler Threads as they become available. Also, creating an ExecutorService for a small task is overkill when there is one available.
Error Reporting
I followed the same approach the scheduler normally uses for CraftAsyncTasks - catch-all and print the exception. However, the log message is slightly different to indicate the task was created through such an Executor.