I am working on an API for a scheduler using a backing ScheduledExecutorService. The basic design, is you register a Provider instance with the Scheduler, and the Scheduler maintains the ScheduledFuture’s for each registered Provider. A Provider is essentially a Runnable that knows how to retrieve firing tasks.
The issue that I am having is what to do when cancelling a scheduled future. The API to cancel a ScheduledFuture takes a boolean parameter allowing the interruption of a Provider which is being fired. I think that it makes sense to alert the Provider when it is being killed along with value of that parameter, so it could do any necessary clean-up.
However, if you alert the Provider instance that it is being killed before just cancelling its ScheduledFuture, there is the possibility that the Provider instance could break the API by blocking until it has completed its execution regardless of the value of that parameter.
On the other side of that, if cancel is called with that value set to true and the ScheduledFuture is cancelled before letting the Provider instance know that it is being killed, it could lose the opportunity to do anything about it.
Note: I cannot use Quartz due to the requirements of the project. Otherwise I would have just used it. Please do not respond telling me to use an alternative framework, as my question is about API design.
Any ideas?
Technically, isn’t this more of an SPI than an API? I think we can expect more of the implementor as a result, so I would notify them of the closure. As a bit of a hedge, I would also make sure that the notification does nothing by default. If you use a listener, don’t register the provider for this event automatically. If you always call a certain method, provide an abstract base class that does nothing for that call.
Here is my justification for expecting more of implementers of an SPI:
If I want to schedule a task I use the ScheduledExecutor API. As an application programmer, I have a use-case that I want to satisfy and I’m trying not to be concerned with the inner workings of how it gets done. As a result, I think APIs should generally be coded very defensively.
Provider is pretty clearly an SPI. The class name “Provider” is a big hint. It knows exactly how it is to be used and is all about low-level details. I am implementing it specifically because the default implementation doesn’t do what I want. I want the maximum degree of flexibility, even at the expense of more effort on my part. Application programmers should not be expected to write one. They might choose one implementation over another, though.