PageRenderTime 26ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/docs/userguide.rst

https://bitbucket.org/omus/apscheduler
ReStructuredText | 405 lines | 281 code | 124 blank | 0 comment | 0 complexity | 3a4d8cf700bc9351559541f0d59178ee MD5 | raw file
  1. ##########
  2. User guide
  3. ##########
  4. Installing APScheduler
  5. ----------------------
  6. The preferred installation method is by using `pip <http://pypi.python.org/pypi/pip/>`_::
  7. $ pip install apscheduler
  8. If you don't have pip installed, you can easily install it by downloading and running
  9. `get-pip.py <https://bootstrap.pypa.io/get-pip.py>`_.
  10. If, for some reason, pip won't work, you can manually `download the APScheduler distribution
  11. <https://pypi.python.org/pypi/APScheduler/>`_ from PyPI, extract and then install it::
  12. $ python setup.py install
  13. Code examples
  14. -------------
  15. The source distribution contains the :file:`examples` directory where you can find many working examples for using
  16. APScheduler in different ways. The examples can also be
  17. `browsed online <https://bitbucket.org/agronholm/apscheduler/src/master/examples/?at=master>`_.
  18. Basic concepts
  19. --------------
  20. APScheduler has four kinds of components:
  21. * triggers
  22. * job stores
  23. * executors
  24. * schedulers
  25. *Triggers* contain the scheduling logic. Each job has its own trigger which determines when the job should be run next.
  26. Beyond their initial configuration, triggers are completely stateless.
  27. *Job stores* house the scheduled jobs. The default job store simply keeps the jobs in memory, but others store them in
  28. various kinds of databases. A job's data is serialized when it is saved to a persistent job store, and deserialized when
  29. it's loaded back from it. Job stores (other than the default one) don't keep the job data in memory, but act as
  30. middlemen for saving, loading, updating and searching jobs in the backend. Job stores must never be shared between
  31. schedulers.
  32. *Executors* are what handle the running of the jobs. They do this typically by submitting the designated callable in a
  33. job to a thread or process pool. When the job is done, the executor notifies the scheduler which them emits an
  34. appropriate event.
  35. *Schedulers* are what bind the rest together. You typically have only one scheduler running in your application.
  36. The application developer doesn't normally deal with the job stores, executors or triggers directly. Instead, the
  37. scheduler provides the proper interface to handle all those. Configuring the job stores and executors is done through
  38. the scheduler, as is adding, modifying and removing jobs.
  39. Choosing the right scheduler, job stores and executors
  40. ------------------------------------------------------
  41. Your choice of scheduler depends mostly on your programming environment and what you'll be using APScheduler for.
  42. Here's a quick guide for choosing a scheduler:
  43. * :class:`~apscheduler.schedulers.blocking.BlockingScheduler`:
  44. use when the scheduler is the only thing running in your process
  45. * :class:`~apscheduler.schedulers.background.BackgroundScheduler`:
  46. use then you're not using any of the frameworks below, and want the scheduler to run in the background inside your
  47. application
  48. * :class:`~apscheduler.schedulers.asyncio.AsyncIOScheduler`:
  49. use if your application uses the asyncio module
  50. * :class:`~apscheduler.schedulers.gevent.GeventScheduler`:
  51. use if your application uses gevent
  52. * :class:`~apscheduler.schedulers.tornado.TornadoScheduler`:
  53. use if you're building a Tornado application
  54. * :class:`~apscheduler.schedulers.twisted.TwistedScheduler`:
  55. use if you're building a Twisted application
  56. * :class:`~apscheduler.schedulers.qt.QtScheduler`:
  57. use if you're building a Qt application
  58. Simple enough, yes?
  59. To pick the appropriate job store, you need to determine whether you need job persistence or not. If you always recreate
  60. your jobs at the start of your application, then you can probably go with the default
  61. (:class:`~apscheduler.jobstores.memory.MemoryJobStore`). But if you need your jobs to persist over scheduler restarts or
  62. application crashes, then your choice usually boils down to what tools are used in your programming environment.
  63. If, however, you are in the position to choose freely, then
  64. :class:`~apscheduler.jobstores.sqlalchemy.SQLAlchemyJobStore` on a `PostgreSQL <http://www.postgresql.org/>`_ backend is
  65. the recommended choice due to its strong data integrity protection.
  66. Likewise, the choice of executors is usually made for you if you use one of the frameworks above.
  67. Otherwise, the default :class:`~apscheduler.executors.pool.ThreadPoolExecutor` should be good enough for most purposes.
  68. If your workload involves CPU intensive operations, you should consider using
  69. :class:`~apscheduler.executors.pool.ProcessPoolExecutor` instead to make use of multiple CPU cores.
  70. You could even use both at once, adding the process pool executor as a secondary executor.
  71. You can find the plugin names of each job store and executor type in their respective API documentation pages.
  72. .. _scheduler-config:
  73. Configuring the scheduler
  74. -------------------------
  75. APScheduler provides many different ways to configure the scheduler. You can use a configuration dictionary or you can
  76. pass in the options as keyword arguments. You can also instantiate the scheduler first, add jobs and configure the
  77. scheduler afterwards. This way you get maximum flexibility for any environment.
  78. The full list of scheduler level configuration options can be found on the API reference of the
  79. :class:`~apscheduler.schedulers.base.BaseScheduler` class. Scheduler subclasses may also have additional options which
  80. are documented on their respective API references. Configuration options for individual job stores and executors can
  81. likewise be found on their API reference pages.
  82. Let's say you want to run BackgroundScheduler in your application with the default job store and the default executor::
  83. from apscheduler.schedulers.background import BackgroundScheduler
  84. scheduler = BackgroundScheduler()
  85. # Initialize the rest of the application here, or before the scheduler initialization
  86. This will get you a BackgroundScheduler with a MemoryJobStore named "default" and a ThreadPoolExecutor named "default"
  87. with a default maximum thread count of 10.
  88. Now, suppose you want more. You want to have *two* job stores using *two* executors and you also want to tweak the
  89. default values for new jobs and set a different timezone.
  90. The following three examples are completely equivalent, and will get you:
  91. * a MongoDBJobStore named "mongo"
  92. * an SQLAlchemyJobStore named "default" (using SQLite)
  93. * a ThreadPoolExecutor named "default", with a worker count of 20
  94. * a ProcessPoolExecutor named "processpool", with a worker count of 5
  95. * UTC as the scheduler's timezone
  96. * coalescing turned off for new jobs by default
  97. * a default maximum instance limit of 3 for new jobs
  98. Method 1::
  99. from pytz import utc
  100. from apscheduler.schedulers.background import BackgroundScheduler
  101. from apscheduler.jobstores.mongodb import MongoDBJobStore
  102. from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
  103. from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
  104. jobstores = {
  105. 'mongo': MongoDBJobStore(),
  106. 'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
  107. }
  108. executors = {
  109. 'default': ThreadPoolExecutor(20),
  110. 'processpool': ProcessPoolExecutor(5)
  111. }
  112. job_defaults = {
  113. 'coalesce': False,
  114. 'max_instances': 3
  115. }
  116. scheduler = BackgroundScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)
  117. Method 2::
  118. from apscheduler.schedulers.background import BackgroundScheduler
  119. # The "apscheduler." prefix is hard coded
  120. scheduler = BackgroundScheduler({
  121. 'apscheduler.jobstores.mongo': {
  122. 'type': 'mongodb'
  123. },
  124. 'apscheduler.jobstores.default': {
  125. 'type': 'sqlalchemy',
  126. 'url': 'sqlite:///jobs.sqlite'
  127. },
  128. 'apscheduler.executors.default': {
  129. 'class': 'apscheduler.executors.pool:ThreadPoolExecutor',
  130. 'max_workers': '20'
  131. },
  132. 'apscheduler.executors.processpool': {
  133. 'type': 'processpool',
  134. 'max_workers': '5'
  135. },
  136. 'apscheduler.job_defaults.coalesce': 'false',
  137. 'apscheduler.job_defaults.max_instances': '3',
  138. 'apscheduler.timezone': 'UTC',
  139. })
  140. Method 3::
  141. from pytz import utc
  142. from apscheduler.schedulers.background import BackgroundScheduler
  143. from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
  144. from apscheduler.executors.pool import ProcessPoolExecutor
  145. jobstores = {
  146. 'mongo': {'type': 'mongodb'},
  147. 'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
  148. }
  149. executors = {
  150. 'default': {'type': 'threadpool', 'max_workers': 20},
  151. 'processpool': ProcessPoolExecutor(max_workers=5)
  152. }
  153. job_defaults = {
  154. 'coalesce': False,
  155. 'max_instances': 3
  156. }
  157. scheduler = BackgroundScheduler()
  158. # .. do something else here, maybe add jobs etc.
  159. scheduler.configure(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)
  160. Starting the scheduler
  161. ----------------------
  162. Starting the scheduler is done by simply calling :meth:`~apscheduler.schedulers.base.BaseScheduler.start` on the
  163. scheduler. For schedulers other than `~apscheduler.schedulers.blocking.BlockingScheduler`, this call will return
  164. immediately and you can continue the initialization process of your application, possibly adding jobs to the scheduler.
  165. For BlockingScheduler, you will only want to call :meth:`~apscheduler.schedulers.base.BaseScheduler.start` after you're
  166. done with any initialization steps.
  167. .. note:: After the scheduler has been started, you can no longer alter its settings.
  168. Adding jobs
  169. -----------
  170. There are two ways to add jobs to a scheduler:
  171. #. by calling :meth:`~apscheduler.schedulers.base.BaseScheduler.add_job`
  172. #. by decorating a function with :meth:`~apscheduler.schedulers.base.BaseScheduler.scheduled_job`
  173. The first way is the most common way to do it. The second way is mostly a convenience to declare jobs that don't change
  174. during the application's run time. The :meth:`~apscheduler.schedulers.base.BaseScheduler.add_job` method returns a
  175. :class:`apscheduler.job.Job` instance that you can use to modify or remove the job later.
  176. You can schedule jobs on the scheduler **at any time**. If the scheduler is not yet running when the job is added, the
  177. job will be scheduled *tentatively* and its first run time will only be computed when the scheduler starts.
  178. It is important to note that if you use an executor or job store that serializes the job, it will add a couple
  179. requirements on your job:
  180. #. The target callable must be globally accessible
  181. #. Any arguments to the callable must be serializable
  182. Of the builtin job stores, only MemoryJobStore doesn't serialize jobs.
  183. Of the builtin executors, only ProcessPoolExecutor will serialize jobs.
  184. .. important:: If you schedule jobs in a persistent job store during your application's initialization, you **MUST**
  185. define an explicit ID for the job and use ``replace_existing=True`` or you will get a new copy of the job every time
  186. your application restarts!
  187. .. tip:: To run a job immediately, omit ``trigger`` argument when adding the job.
  188. Removing jobs
  189. -------------
  190. When you remove a job from the scheduler, it is removed from its associated job store and will not be executed anymore.
  191. There are two ways to make this happen:
  192. #. by calling :meth:`~apscheduler.schedulers.base.BaseScheduler.remove_job` with the job's ID and job store alias
  193. #. by calling :meth:`~apscheduler.job.Job.remove` on the Job instance you got from
  194. :meth:`~apscheduler.schedulers.base.BaseScheduler.add_job`
  195. The latter method is probably more convenient, but it requires that you store somewhere the
  196. :class:`~apscheduler.job.Job` instance you received when adding the job. For jobs scheduled via the
  197. :meth:`~apscheduler.schedulers.base.BaseScheduler.scheduled_job`, the first way is the only way.
  198. If the job's schedule ends (i.e. its trigger doesn't produce any further run times), it is automatically removed.
  199. Example::
  200. job = scheduler.add_job(myfunc, 'interval', minutes=2)
  201. job.remove()
  202. Same, using an explicit job ID::
  203. scheduler.add_job(myfunc, 'interval', minutes=2, id='my_job_id')
  204. scheduler.remove_job('my_job_id')
  205. Pausing and resuming jobs
  206. -------------------------
  207. You can easily pause and resume jobs through either the :class:`~apscheduler.job.Job` instance or the scheduler itself.
  208. When a job is paused, its next run time is cleared and no further run times will be calculated for it until the job is
  209. resumed. To pause a job, use either method:
  210. * :meth:`apscheduler.job.Job.pause`
  211. * :meth:`apscheduler.schedulers.base.BaseScheduler.pause_job`
  212. To resume:
  213. * :meth:`apscheduler.job.Job.resume`
  214. * :meth:`apscheduler.schedulers.base.BaseScheduler.resume_job`
  215. Getting a list of scheduled jobs
  216. --------------------------------
  217. To get a machine processable list of the scheduled jobs, you can use the
  218. :meth:`~apscheduler.schedulers.base.BaseScheduler.get_jobs` method. It will return a list of
  219. :class:`~apscheduler.job.Job` instances. If you're only interested in the jobs contained in a particular job store,
  220. then give a job store alias as the second argument.
  221. As a convenience, you can use the :meth:`~apscheduler.schedulers.base.BaseScheduler.print_jobs` method which will print
  222. out a formatted list of jobs, their triggers and next run times.
  223. Modifying jobs
  224. --------------
  225. You can modify any job attributes by calling either :meth:`apscheduler.job.Job.modify` or
  226. :meth:`~apscheduler.schedulers.base.BaseScheduler.modify_job`. You can modify any Job attributes except for ``id``.
  227. Example::
  228. job.modify(max_instances=6, name='Alternate name')
  229. If you want to reschedule the job -- that is, change its trigger, you can use either
  230. :meth:`apscheduler.job.Job.reschedule` or :meth:`~apscheduler.schedulers.base.BaseScheduler.reschedule_job`.
  231. These methods construct a new trigger for the job and recalculate its next run time based on the new trigger.
  232. Example::
  233. scheduler.reschedule_job('my_job_id', trigger='cron', minute='*/5')
  234. Shutting down the scheduler
  235. ---------------------------
  236. To shut down the scheduler::
  237. scheduler.shutdown()
  238. By default, the scheduler shuts down its job stores and executors and waits until all currently executing jobs are
  239. finished. If you don't want to wait, you can do::
  240. scheduler.shutdown(wait=False)
  241. This will still shut down the job stores and executors but does not wait for any running
  242. tasks to complete.
  243. Limiting the number of concurrently executing instances of a job
  244. ----------------------------------------------------------------
  245. By default, only one instance of each job is allowed to be run at the same time.
  246. This means that if the job is about to be run but the previous run hasn't finished yet, then the latest run is
  247. considered a misfire. It is possible to set the maximum number of instances for a particular job that the scheduler will
  248. let run concurrently, by using the ``max_instances`` keyword argument when adding the job.
  249. Missed job executions and coalescing
  250. ------------------------------------
  251. Sometimes the scheduler may be unable to execute a scheduled job at the time it was scheduled to run.
  252. The most common case is when a job is scheduled in a persistent job store and the scheduler is shut down and restarted
  253. after the job was supposed to execute. When this happens, the job is considered to have "misfired".
  254. The scheduler will then check each missed execution time against the job's ``misfire_grace_time`` option (which can be
  255. set on per-job basis or globally in the scheduler) to see if the execution should still be triggered.
  256. This can lead into the job being executed several times in succession.
  257. If this behavior is undesirable for your particular use case, it is possible to use `coalescing` to roll all these
  258. missed executions into one. In other words, if coalescing is enabled for the job and the scheduler sees one or more
  259. queued executions for the job, it will only trigger it once. No misfire events will be sent for the "bypassed" runs.
  260. .. _scheduler-events:
  261. Scheduler events
  262. ----------------
  263. It is possible to attach event listeners to the scheduler. Scheduler events are fired on certain occasions, and may
  264. carry additional information in them concerning the details of that particular event.
  265. It is possible to listen to only particular types of events by giving the appropriate ``mask`` argument to
  266. :meth:`~apscheduler.schedulers.base.BaseScheduler.add_listener`, OR'ing the different constants together.
  267. The listener callable is called with one argument, the event object.
  268. See the documentation for the :mod:`~apscheduler.events` module for specifics on the available events and their
  269. attributes.
  270. Example::
  271. def my_listener(event):
  272. if event.exception:
  273. print('The job crashed :(')
  274. else:
  275. print('The job worked :)')
  276. scheduler.add_listener(my_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
  277. Reporting bugs
  278. --------------
  279. .. include:: ../README.rst
  280. :start-after: Reporting bugs
  281. --------------