flask-production
================
Cherrypy prod server for Flask + parallel task scheduler
|Python 3.7| |license| |pytest|
Installation
---------------------
.. code:: sh
pip install flask_production
Usage example
-------------
CherryFlask
~~~~~~~~~~~~~~~
``Cherrypy`` server on top of ``Flask`` app
.. code:: python
CherryFlask(app, scheduler=None, silent=False)
Parameters:
- **app** *(Flask)*: ``Flask`` application
- **scheduler** *(TaskScheduler)*: task scheduler to run in parallel with ``Flask`` app
- **silent** *(bool)*: don't print logs
- default False
.. code:: python
from flask import Flask
from flask_production import CherryFlask
app = Flask(__name__)
...
cherry = CherryFlask(app)
cherry.run(host="0.0.0.0", port=8080, threads=5, debug=False)
|
TaskScheduler
~~~~~~~~~~~~~~~
| Main class to setup, run and manage jobs
.. code:: python
TaskScheduler(check_interval=5,
holidays_calendar=None,
tzname=None,
on_job_error=None,
log_filepath=None,
log_maxsize=5*1024*1024, # 5 MB
log_backups=1,
startup_grace_mins=0, # minutes
persist_states=True,
state_handler=None)
Parameters:
- **check_interval** *(int)*: how often to check for pending jobs
- default 5 seconds
- **holidays_calendar** *(holidays.HolidayBase)*: calendar to use for intervals like ``businessday``
- default US holidays
- **tzname** *(str)*: name of timezone as supported by dateutil.tz
- **on_job_error** *(func(e))*: function to call if any job fails
- **log_filepath** *(path)*: file to write logs to
- **log_maxsize** *(int)*: byte limit per log file
- default 5 mb (only effective if log_filepath is provided)
- **log_backups** *(int)*: number of backups of logs to retain
- default 1 (only effective if log_filepath is provided)
- **startup_grace_mins** *(int)*: grace period for tasks in case a schedule was missed because of app restart
- default 0
- **persist_states** *(bool)*: store job logs and read back on app restart
- default True (logs will be stored)
- **state_handler** *(.state.BaseStateHandler)*: different handler backends to store job logs
- default .state.FileSystemState (logs will be stored in a unique data directory)
Standalone usage
.. code:: python
from flask_production import TaskScheduler
sched = TaskScheduler(check_interval=2)
# Run every minute
sched.every(60).do(foo)
# Run on end of every month (with strict_date False)
sched.every("31st").strict_date(False).at("08:00").do(foo)
# Run every weekday
sched.every("weekday").at("08:00").do(lambda:bar())
sched.every("weekday").at("08:00").timezone("Europe/London").do(lambda:bar())
# catch() will run on job error
example_job = sched.every("weekday").at("09:00").do(lambda:failing()).catch(lambda e: print(e))
# access job information and status as dict
print(example_job.to_dict())
print(sched.jobs[-1].to_dict()) # same job
sched.start() # starts the task scheduler and blocks
..
Instead of ``sched.start()``, TaskScheduler can be run in parallel with a Flask application using ``CherryFlask``
.. code:: python
from flask import Flask
from flask_production import TaskScheduler, CherryFlask
app = Flask(__name__)
...
sched = TaskScheduler()
...
cherry = CherryFlask(app, scheduler=sched)
cherry.run(host="0.0.0.0", port=8080, threads=5, debug=False)
..
|
TaskMonitor
~~~~~~~~~~~~~~
| The TaskScheduler exposes a list of Job objects through the ``.jobs`` attribute
| Job information and logs from the last execution are available using the ``.to_dict()`` method
| TaskMonitor uses these features to provide a web interface to view and rerun tasks
.. code:: python
TaskMonitor(
app,
sched,
display_name=None,
endpoint="@taskmonitor",
homepage_refresh=30,
taskpage_refresh=5,
can_rerun=True,
can_disable=True)
Parameters:
- **app** *(int)*: ``Flask`` application
- **sched** *(TaskScheduler)*: task scheduler with task definitions
- **display_name** *(str)*: name of the application to be displayed
- default app.name
- **endpoint** *(str)*: URL endpoint where the taskmonitor can be viewed
- default "@taskmonitor"
- **homepage_refresh** *(int)*: home page auto refresh interval (in seconds)
- default 30
- **taskpage_refresh** *(int)*: task page auto refresh interval (in seconds)
- default 5
- **can_rerun** *(bool)*: if True adds rerun button to job page
- default True
- **can_disable** *(bool)*: if True adds disable button to job page
- default True
.. code:: python
from flask import Flask
from flask_production import CherryFlask, TaskScheduler
from flask_production.plugins import TaskMonitor
app = Flask(__name__)
sched = TaskScheduler(check_interval=2)
monitor = TaskMonitor(app, sched)
print(monitor._endpoint) # /@taskmonitor
# Run every minute
sched.every(60).do(foo)
cherry = CherryFlask(app, scheduler=sched)
cherry.run(host="0.0.0.0", port=8080) # localhost:8080/@taskmonitor
`Example Gist
here <https://gist.github.com/shashfrankenstien/5cfa8821d74c24fb0a01b979d434e5bb>`__
TODO:
~~~~~~~~~~~~~~
| scheduler - function argument validation
.. |Python 3.7| image:: https://img.shields.io/badge/python-3.7+-blue.svg
.. |license| image:: https://img.shields.io/github/license/shashfrankenstien/flask_production
.. |pytest| image:: https://github.com/shashfrankenstien/Flask_Production/workflows/pytest/badge.svg
Raw data
{
"_id": null,
"home_page": "https://github.com/shashfrankenstien/Flask_Production",
"name": "flask-production",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "Shashank Gopikrishna",
"author_email": "shashank.gopikrishna@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/cc/df/51ebdd6a9a7f2a27768f31712c07e2df85064515e5f1c9bc372ab70b5d59/flask_production-3.1.2.tar.gz",
"platform": null,
"description": "flask-production\n================\n\nCherrypy prod server for Flask + parallel task scheduler\n\n|Python 3.7| |license| |pytest|\n\nInstallation\n---------------------\n\n.. code:: sh\n\n pip install flask_production\n\nUsage example\n-------------\n\nCherryFlask\n~~~~~~~~~~~~~~~\n``Cherrypy`` server on top of ``Flask`` app\n\n.. code:: python\n\n CherryFlask(app, scheduler=None, silent=False)\n\n\nParameters:\n\n- **app** *(Flask)*: ``Flask`` application\n\n- **scheduler** *(TaskScheduler)*: task scheduler to run in parallel with ``Flask`` app\n\n- **silent** *(bool)*: don't print logs\n - default False\n\n\n\n.. code:: python\n\n from flask import Flask\n from flask_production import CherryFlask\n\n app = Flask(__name__)\n ...\n\n cherry = CherryFlask(app)\n cherry.run(host=\"0.0.0.0\", port=8080, threads=5, debug=False)\n\n|\n\n\nTaskScheduler\n~~~~~~~~~~~~~~~\n| Main class to setup, run and manage jobs\n\n\n.. code:: python\n\n TaskScheduler(check_interval=5,\n holidays_calendar=None,\n tzname=None,\n on_job_error=None,\n log_filepath=None,\n log_maxsize=5*1024*1024, # 5 MB\n log_backups=1,\n startup_grace_mins=0, # minutes\n persist_states=True,\n state_handler=None)\n\n\nParameters:\n\n- **check_interval** *(int)*: how often to check for pending jobs\n - default 5 seconds\n\n- **holidays_calendar** *(holidays.HolidayBase)*: calendar to use for intervals like ``businessday``\n - default US holidays\n\n- **tzname** *(str)*: name of timezone as supported by dateutil.tz\n- **on_job_error** *(func(e))*: function to call if any job fails\n- **log_filepath** *(path)*: file to write logs to\n- **log_maxsize** *(int)*: byte limit per log file\n - default 5 mb (only effective if log_filepath is provided)\n- **log_backups** *(int)*: number of backups of logs to retain\n - default 1 (only effective if log_filepath is provided)\n- **startup_grace_mins** *(int)*: grace period for tasks in case a schedule was missed because of app restart\n - default 0\n- **persist_states** *(bool)*: store job logs and read back on app restart\n - default True (logs will be stored)\n- **state_handler** *(.state.BaseStateHandler)*: different handler backends to store job logs\n - default .state.FileSystemState (logs will be stored in a unique data directory)\n\n\nStandalone usage\n\n.. code:: python\n\n from flask_production import TaskScheduler\n\n sched = TaskScheduler(check_interval=2)\n\n # Run every minute\n sched.every(60).do(foo)\n\n # Run on end of every month (with strict_date False)\n sched.every(\"31st\").strict_date(False).at(\"08:00\").do(foo)\n\n # Run every weekday\n sched.every(\"weekday\").at(\"08:00\").do(lambda:bar())\n sched.every(\"weekday\").at(\"08:00\").timezone(\"Europe/London\").do(lambda:bar())\n\n # catch() will run on job error\n example_job = sched.every(\"weekday\").at(\"09:00\").do(lambda:failing()).catch(lambda e: print(e))\n\n # access job information and status as dict\n print(example_job.to_dict())\n print(sched.jobs[-1].to_dict()) # same job\n\n sched.start() # starts the task scheduler and blocks\n..\n\n\nInstead of ``sched.start()``, TaskScheduler can be run in parallel with a Flask application using ``CherryFlask``\n\n.. code:: python\n\n from flask import Flask\n from flask_production import TaskScheduler, CherryFlask\n\n app = Flask(__name__)\n ...\n\n sched = TaskScheduler()\n ...\n\n cherry = CherryFlask(app, scheduler=sched)\n cherry.run(host=\"0.0.0.0\", port=8080, threads=5, debug=False)\n\n..\n\n\n|\n\nTaskMonitor\n~~~~~~~~~~~~~~\n\n| The TaskScheduler exposes a list of Job objects through the ``.jobs`` attribute\n| Job information and logs from the last execution are available using the ``.to_dict()`` method\n| TaskMonitor uses these features to provide a web interface to view and rerun tasks\n\n\n\n.. code:: python\n\n TaskMonitor(\n app,\n sched,\n display_name=None,\n endpoint=\"@taskmonitor\",\n homepage_refresh=30,\n taskpage_refresh=5,\n can_rerun=True,\n can_disable=True)\n\nParameters:\n\n- **app** *(int)*: ``Flask`` application\n- **sched** *(TaskScheduler)*: task scheduler with task definitions\n- **display_name** *(str)*: name of the application to be displayed\n - default app.name\n\n- **endpoint** *(str)*: URL endpoint where the taskmonitor can be viewed\n - default \"@taskmonitor\"\n- **homepage_refresh** *(int)*: home page auto refresh interval (in seconds)\n - default 30\n- **taskpage_refresh** *(int)*: task page auto refresh interval (in seconds)\n - default 5\n- **can_rerun** *(bool)*: if True adds rerun button to job page\n - default True\n- **can_disable** *(bool)*: if True adds disable button to job page\n - default True\n\n\n.. code:: python\n\n from flask import Flask\n from flask_production import CherryFlask, TaskScheduler\n from flask_production.plugins import TaskMonitor\n\n app = Flask(__name__)\n sched = TaskScheduler(check_interval=2)\n\n monitor = TaskMonitor(app, sched)\n print(monitor._endpoint) # /@taskmonitor\n\n # Run every minute\n sched.every(60).do(foo)\n\n cherry = CherryFlask(app, scheduler=sched)\n cherry.run(host=\"0.0.0.0\", port=8080) # localhost:8080/@taskmonitor\n\n`Example Gist\nhere <https://gist.github.com/shashfrankenstien/5cfa8821d74c24fb0a01b979d434e5bb>`__\n\n\nTODO:\n~~~~~~~~~~~~~~\n\n| scheduler - function argument validation\n\n\n.. |Python 3.7| image:: https://img.shields.io/badge/python-3.7+-blue.svg\n.. |license| image:: https://img.shields.io/github/license/shashfrankenstien/flask_production\n.. |pytest| image:: https://github.com/shashfrankenstien/Flask_Production/workflows/pytest/badge.svg\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "cherrypy server for Flask + task scheduler and monitor",
"version": "3.1.2",
"project_urls": {
"Homepage": "https://github.com/shashfrankenstien/Flask_Production"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "20316e429ea923c7eb8175a89fa14ecd8cd931c20398091b2ba327b78b73899b",
"md5": "7f0fc378cf99ad6e204c74afc66cec67",
"sha256": "96064c40e9384916b68c165ad41d64ac657f28073d80fd16f9c8943f1dbaebd3"
},
"downloads": -1,
"filename": "flask_production-3.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7f0fc378cf99ad6e204c74afc66cec67",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 36978,
"upload_time": "2024-08-04T16:58:20",
"upload_time_iso_8601": "2024-08-04T16:58:20.737434Z",
"url": "https://files.pythonhosted.org/packages/20/31/6e429ea923c7eb8175a89fa14ecd8cd931c20398091b2ba327b78b73899b/flask_production-3.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "ccdf51ebdd6a9a7f2a27768f31712c07e2df85064515e5f1c9bc372ab70b5d59",
"md5": "2e627c00c66f46ebbdb8e2984d445934",
"sha256": "5a7be5060725f9ab0a205b884e20fbcd20d0ab3ccc29d490c4bf822498684250"
},
"downloads": -1,
"filename": "flask_production-3.1.2.tar.gz",
"has_sig": false,
"md5_digest": "2e627c00c66f46ebbdb8e2984d445934",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 38202,
"upload_time": "2024-08-04T16:58:22",
"upload_time_iso_8601": "2024-08-04T16:58:22.790696Z",
"url": "https://files.pythonhosted.org/packages/cc/df/51ebdd6a9a7f2a27768f31712c07e2df85064515e5f1c9bc372ab70b5d59/flask_production-3.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-04 16:58:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "shashfrankenstien",
"github_project": "Flask_Production",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "flask-production"
}