Solved Delayed Tasks Canceled on Disable?

Discussion in 'Spigot Plugin Development' started by egg82, Apr 18, 2017.

  1. Odd question - if a plugin is disabled in the middle of a delayed task, is the delayed task immediately canceled by the server, or allowed to finish? On that same note, are repeated tasks allowed to finish once more and then canceled, or are they canceled immediately?

    I've tried to look this up, but the most I got was this article that says "They will continue to execute until completed, or canceled, or your plugin is disabled."
    That is somewhat helpful, but it doesn't answer my question explicitly. I also don't even really know where to look in the source for a question like this. I'm hoping someone here has already figured it out.
  2. Sounds clear to me. Once your plugin gets disabled, no new call of your Runnable (#run) will be executed.
    That's why you need to pass your plugin instance, when scheduling a new Task. So bukkit knows to which plugin the task belongs to and knows when to cancel it.
    • Delayed tasks won't fire
    • Repeating tasks won't be fired again
    • Already fired tasks will execute till their end
    Altough i'm pretty sure, i might be wrong.
    In General there are two ways, if you want this detailed Information about the behaviour:
    • Test it
    • Look into decompiled CraftBukkit sources
    "org.bukkit.plugin.SimplePluginManager#disablePlugin" calls "org.bukkit.craftbukkit.v1_10_R1.scheduler.CraftScheduler#cancelTasks". The CraftScheduler keeps all plugin instance references for all scheduled tasks, so it exactly knows which ones are to cancel (example of 1.10.2).
    #2 Michel_0, Apr 18, 2017
    Last edited: Apr 18, 2017
  3. That's kinda what I figured. So the run() function isn't called at all, even if the Runnable was created before the plugin was disabled. What about async tasks, though? Would they be canceled halfway through the run() function, or allowed to finish as well? What about repeated async tasks?

    Yeah, I wasn't sure where in the source that behavior would be located. Also, I was hoping that instead of creating a whole new test plugin someone else would have already looked into this before and had an answer.
  4. It's completely irrelevant, when you instantiate a new instance of the Runnable you want to schedule. You even can schedule the same Runnable several times. It's only relevant when you schedule your task to be executed.

    Same. If they're triggered before the synchronous tick, when their plugin will be disabled, they will be executed. If they would be executed after the synchronous task, when their plugin has been disabled, they won't be executed.

    Nope. The only relevant point is, when the #run gets fired. Once #run has been fired, there is no way back, too late to cancel. The Task scheduler doesn't care, how long it takes to execute the #run. Once fired it's all done for the task scheduler, it doesn't care if or when #run finishes executing.

    EDIT: The only onclear thing i don't know, is how synchronous scheduled tasks behave, if their plugin will be disabled right in the same server tick they would fire. If you want to know it detailed like this, you really should test it.
    • Agree Agree x 1
  5. Ah, I believe I understand how the system works now.

    cancelTask()->Scheduler->Create Runnable

    Plugin->Create Runnable
    loop plugins
    Scheduler->If plugin disabled, run cancelTask()
    Scheduler->Check if run condition is met->Runnable#run()
    end loop
    Scheduler->Run canceled task Runnable

    Meaning each call to run() must fully complete (even if the task is asynchronous) and all tasks that are scheduled to run on that tick will be run before they are canceled.
    If a Runnable is created but not run, it will be canceled if the plugin is disabled.