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
Add support for scheduling global callbacks #2661
Conversation
@MarcSkovMadsen Suggestions on the API and functionality here would be appreciated. |
Codecov Report
@@ Coverage Diff @@
## master #2661 +/- ##
========================================
Coverage 83.09% 83.10%
========================================
Files 193 193
Lines 25753 25931 +178
========================================
+ Hits 21400 21550 +150
- Misses 4353 4381 +28
Continue to review full report at Codecov.
|
One thing the above will not support is a physicist wanting to schedule a job at the next solar eclipse. Or maybe in trading the next trading day etc. For that a custom function But the above api is nice and covers most of my use cases. |
This is something I'm currently testing out class JobScheduler(param.Parameterized):
"""The JobScheduler enables scheduling jobs in a global or session context"""
job = param.ClassSelector(class_=Job, doc="The Job to schedule")
next_run_utc_func = param.Parameter(
precedence=-1,
doc="""
A function taking a datetime (utcnow) as argument and returning the next utc datetime to
schedule the job.
""",
)
context = param.ObjectSelector(
default="global",
objects=["global"],
constant=True,
doc="""
Either global or session. If session the JobScheduler will stop running when the session
is deleted.
""",
)
next_run_utc = param.Date(
constant=True, doc="""The next utc datetime the job is scheduled for"""
)
logger = param.ClassSelector(class_=Logger)
view = param.Parameter()
def __init__(self, **params):
super().__init__(**params)
self.view = pn.Param(self, parameters=["job", "next_run_utc"])
self._schedule_next_run()
def _run_and_reschedule(self):
self.job.run() # pylint: disable=no-member
self._schedule_next_run()
def _schedule_next_run(self):
with param.edit_constant(self):
self._add_callback()
def _add_callback(self):
IOLoop.current().add_callback(self._add_timeout)
def _add_timeout(self):
utcnow=datetime.datetime.utcnow()
try:
self.next_run_utc = self.next_run_utc_func(utcnow)
deadline=self.next_run_utc-utcnow
IOLoop.current().add_timeout(
deadline=deadline, callback=self._run_and_reschedule # pylint: disable=no-member
)
self._log_info(f"Next run of {self.job.name} was scheduled to {self.next_run_utc}")
except Exception as ex:
self._log_error(f"Could not add timeout {ex}")
@staticmethod
def _get_miliseconds_to_next_run(now, next_run):
return (next_run - now).seconds * 1000
def _log_info(self, message):
if self.logger:
self.logger.info(self.name + " - " + message) # pylint: disable=no-member
def _log_error(self, message):
if self.logger:
self.logger.error(self.name + " - " + message) # pylint: disable=no-member |
Note for my self. When this PR is implemented and released I should rewrite https://discourse.holoviz.org/t/panel-starting-a-stream-of-data/2709/4?u=marc. |
2a55f74
to
8898cda
Compare
f9f2ad8
to
8537ddd
Compare
Since jobs are named, it seems like previously scheduled jobs could be canceled with The |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My general feedback would be to document this a little more by:
- giving examples of tasks a user may want to register
- making it clearer what kind of callbacks should be used and what they allow, between
schedule
andadd_next_tick_callback
andadd_next_tick_callback
andonload
and--warm
and--setup
...
Co-authored-by: James A. Bednar <jbednar@users.noreply.github.com>
d3a61a6
to
b5c9e1b
Compare
Often times you want to run a task periodically independently of the apps being served, e.g. to refresh cached data at certain intervals or for any other number of reasons. This PR introduces
pn.state.schedule
that allows scheduling tasks at periodic intervals either as declared by aperiod
or acron
expression.One important caveat here is that the callback to be scheduled may not be defined in the same module as the app being run so it must either be imported from an external module OR it may be declared as part of a setup script. A setup script may now be provided using the new
--setup
argument topanel serve
which may configure the Panel apps in any number of ways, e.g. by changing thepn.config
defaults, populating thepn.state.cache
or to schedule tasks withpn.state.schedule
.Implements #2657