How update Managed Packages (2GP) if one of the Apex classes is scheduled Apex

According to this question on the Developerforce platform, a user discovered that you can install an update even while a Schedueable class is scheduled.

I can't find any documentation on the matter, but this makes sense; ISVs need to be able to push out updates, sometimes forcefully (see Push Upgrades), which wouldn't be possible if a user could just permanently lock the package from upgrading by scheduling it.

For example, let's say I wanted to prevent a package from updating, I could deploy this code to production:

public class HahaIBlockedYourUpdate implements Schedulable {
  public void execute(SchedulableContext) {
    SomeNamespace.SomeClassFromNS value;
  }
}

Schedule the class, and "presto!", the ISV can no longer push updates to the subscriber if they have even a single global class in their package (since you can't access public/private classes inside a package).

So, while undocumented, it should be safe to update the class if you need to. Do be aware that you may need to notify users of your package update, since the class may break if you make certain changes to the class. This is because a scheduled class is serialized when it is scheduled, so changing variable names or types may affect the serialized state, resulting in runtime errors.

You should be very careful changing your Schedulable class, but if you need to make an update, you won't need to worry about previously scheduled classes from blocking an update.


Just to add to this, it definitely use to be an issue in 1GP packages, which is why you see posts about it. I think it was Dan Appleman who suggested using this pattern in scheduled jobs to avoid that issue, and I still use it today. So I think sfdcfox is correct that managed packages basically install as if "Allow deployments of components when corresponding Apex jobs are pending or in progress" is turned on, but something like the pattern below would also avoid likely conflicts if you start encountering them

global class KWDATA_Scheduler implements Schedulable {

    global void execute(SchedulableContext sc) {
        Type t = Type.forName('KWDATA_RequestData');
        KWDATA_RequestData kwd = (KWDATA_RequestData) t.newinstance();
        kwd.RequestData();
    }

}