Skip to content

Commit

Permalink
Added Non blocking Scheduling doc
Browse files Browse the repository at this point in the history
added documentation regarding scheduling task and corutines in non-blocking loop
  • Loading branch information
Josef committed Mar 21, 2021
1 parent 0bab53e commit 4774433
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 2 deletions.
3 changes: 2 additions & 1 deletion AUTHORS.rst
Expand Up @@ -29,4 +29,5 @@ Thanks to all the wonderful folks who have contributed to schedule over the year
- Skenvy <https://github.com/skenvy>
- zcking <https://github.com/zcking>
- Martin Thoma <https://github.com/MartinThoma>
- ebllg <https://github.com/ebllg>
- ebllg <https://github.com/ebllg>
- 07pepa <https://github.com/07pepa>
92 changes: 92 additions & 0 deletions docs/async-support.rst
@@ -0,0 +1,92 @@
Nonblocking scheduling with coroutines
======================================
Fist is good to explain what we mean by nonblocking scheduling.
Most of time during scheduling will be spent in spinning on time.sleep


What it allows
------------------
This allows better handling signals during long sleeps (day long sleeps are relatively fine)
and exiting scheduling loop right away after signal reliably (can behave unpredictably).
This may lead to better usage of cpu (due just in time wakeup for next task).
It can also allow running scheduler in asyncio application without blocking and it can force scheduling loop to run.
it also allows scheduling of coroutines

How?
----
This code will only run on Wednesday regular task and Sunday coroutine task.
Nothing is running in between but code not hangs on system signals and exits loop (that is impossible without coroutines).

.. code-block:: python
import schedule
import asyncio
print(schedule.every().wednesday.do(lambda: print("It is Wednesday...")))
def wrap_coroutine(c):
asyncio.create_task(c()) # coroutine must always be wrapped in create task
async def something_useful():
await asyncio.sleep(1) # some useful async function
print("is is sunday")
print(schedule.every().sunday.do(lambda: wrap_coroutine(something_useful)))
terminateEvent = None
def setup(): #needs to run on asyncio loop
import signal
from sys import platform
global terminateEvent
terminateEvent = asyncio.Event() #needs to run on asyncio loop
def terminate(signum):
print(f"sayonara, I received {signum}")
terminateEvent.set() # kill loop
isLinux = platform.system() == "Linux" or platform.system() == "Darwin" # only unix has add_signal_handler
if isLinux:
loop = asyncio.get_running_loop() #needs to run on asyncio loop
def linux_handler(signum):
def handler():
terminate(signum)
loop.add_signal_handler(signum, handler)
handleSignal = linux_handler
else:
def windows_handler(signum):
def wrapper(sig, frame):
terminate(sig)
signal.signal(signum, wrapper)
handleSignal = windows_handler
handleSignal(signal.SIGINT)
async def kill_sleep(seconds):
try:
return await asyncio.wait_for(terminateEvent.wait(), timeout=seconds)
except asyncio.TimeoutError:
return False
async def main():
setup()
while not await kill_sleep(schedule.idle_seconds()): # will sleep until next
schedule.run_pending()
asyncio.run(main())
DrawBacks
----------
Only drawback is precision of asyncio.wait_for timeout.
8 changes: 8 additions & 0 deletions docs/faq.rst
Expand Up @@ -68,6 +68,14 @@ How to continuously run the scheduler without blocking the main thread?
-----------------------------------------------------------------------
:doc:`Background Execution<background-execution>`.

Better handling signals during time.sleep
-----------------------------------------
:doc:`non blocking scheduling<async-support>`

Does schedule support coroutines?
-------------------------------
:doc:`yes <async-support>`

Another question?
-----------------
If you are left with an unanswered question, `browse the issue tracker <http://github.com/dbader/schedule/issues>`_ to see if your question has been asked before.
Expand Down
3 changes: 2 additions & 1 deletion docs/index.rst
Expand Up @@ -16,11 +16,12 @@ Python job scheduling for humans. Run Python functions (or any other callable) p
- A simple to use API for scheduling jobs, made for humans.
- In-process scheduler for periodic jobs. No extra processes needed!
- Very lightweight and no external dependencies.
- Supports :doc:`non blocking/async scheduling<async-support>`
- Excellent test coverage.
- Tested on Python 3.6, 3.7, 3.8 and 3.9


:doc:`Example <examples>`
:doc:`Example<examples>`
-------------------------

.. code-block:: bash
Expand Down

0 comments on commit 4774433

Please sign in to comment.