├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── __init__.py ├── celery_tasktigger ├── __init__.py └── decorator.py ├── example.py ├── images └── logo.jpg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask instance folder 59 | instance/ 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # IPython Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # dotenv 80 | .env 81 | 82 | # virtualenv 83 | venv/ 84 | ENV/ 85 | 86 | # Spyder project settings 87 | .spyderproject 88 | 89 | # Rope project settings 90 | .ropeproject 91 | 92 | # ide 93 | .idea 94 | 95 | images/*.gif 96 | images/*.lpop -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Boyle Gu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | celery-task-tigger 2 | ==== 3 | 4 | [![release](https://img.shields.io/badge/release-0.4-blue.svg)]() 5 | [![license](https://img.shields.io/badge/license-MIT-blue.svg)]() 6 | [![celery](https://img.shields.io/badge/celery-3%7C4-brightgreen.svg)]() 7 | 8 | 9 | 10 | 11 |

12 | sanic_vue 13 | 14 |

A controllable timing task widgets with Celery

15 | 16 | ## About 17 | 18 | As is known to all, Celery have a already provides periodic task and it's very perfit. But, Assume this case: After my task was called, I hope it's task can frequency of execution, and when celery task was started. 19 | 20 | The above case, Periodic task is hard to practice, Becacuse it's depend on celery beat. ``celery-task-tigger`` do it over simple packaging or implement for solution to do it. 21 | 22 | 23 | ## Installation 24 | 25 | ~~~python 26 | pip install celery-task-tigger 27 | 28 | ~~~ 29 | 30 | ## Useage 31 | 32 | Assume you have aleady install celery and can do it. 33 | 34 | ### Bases 35 | 36 | Option `max_times` is must be appoint. 37 | 38 | ~~~python 39 | from celery_tasktigger.decorator import tigger_task 40 | 41 | @app.task(bind=True) 42 | @tigger_task(max_times='forever') # forever is expressed unlimited time 43 | def add(self, x, y): 44 | return x + y 45 | 46 | ~~~ 47 | 48 | ### max_times 49 | 50 | Option `max_times`: The maximum number of execute the task times. 51 | 52 | Type: ***int*** 53 | 54 | > Note: The value ***'forever'*** is expressed unlimited time. 55 | 56 | Example: 57 | 58 | ~~~python 59 | @app.task(bind=True) 60 | @tigger_task(max_times=3) # after execute 3 times, raise an exception 61 | def add(self, x, y): 62 | return x + y 63 | 64 | ~~~ 65 | 66 | ### countdown 67 | 68 | Option `countdown`: You can also provide the countdown argument to execute. 69 | 70 | Type: ***int*** 71 | 72 | Default: 1 (seconds) 73 | 74 | Example: 75 | 76 | ~~~python 77 | @app.task(bind=True) 78 | @tigger_task(max_times='forever', countdown=3) # each execute in 3 seconds 79 | def add(self, x, y): 80 | return x + y 81 | 82 | ~~~ 83 | 84 | OR 85 | 86 | ~~~python 87 | @app.task(bind=True) 88 | @tigger_task(max_times='forever') 89 | def add(self, x, y, countdown=3): # you also can define formal parameter in task 90 | return x + y 91 | 92 | ~~~ 93 | 94 | ## How To Calling Task 95 | 96 | ~~~~python 97 | >> from example import add 98 | >> add.apply_async((1,2)) 99 | ~~~~ 100 | 101 | you can also delayed execute task, as follow: 102 | 103 | ~~~~python 104 | >> from example import add 105 | >> add.apply_async((1,2), countdown=4) # after 4 seconds, begin start task 106 | # add.apply_async((1,2),{'countdown': 2} countdown=4) ## after 4 seconds, begin start task and interval in 2 seconds 107 | ~~~~ 108 | 109 | > About Celery Task, Please see below for details: 110 | > [Celery Calling-Tasks Document](http://docs.jinkan.org/docs/celery/userguide/calling.html) 111 | 112 | ## How To Stop 113 | 114 | if you appoint `max_times='forever'` or provides the bigger values of max_times, you must stop it in programe. 115 | 116 | ~~~~python 117 | >> result = add.apply_async((1,2)) 118 | >> result.revoke() 119 | or 120 | >> from mycelery import app 121 | >> app.control.revoke('task_id') 122 | ~~~~ 123 | 124 | > See below for details: 125 | > [Celery Document——FAQ](http://docs.jinkan.org/docs/celery/faq.html#can-i-cancel-the-execution-of-a-task) 126 | 127 | ## Some screenshots 128 | 129 | ![](http://i1.piimg.com/536217/1ae9af3a274de4c7.gif) 130 | 131 | ## Features 132 | 133 | - 100% full compatible with Celery 3 | 4 134 | 135 | - the frequency of execution for task 136 | 137 | - ...and many other stuff (o,0) 138 | 139 | 140 | ## Author 141 | 142 | - Boyle Gu 143 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import -------------------------------------------------------------------------------- /celery_tasktigger/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Handled exceptions raised by celery-task-tigger 3 | 4 | """ 5 | from __future__ import unicode_literals 6 | 7 | 8 | class LoopCaptureTag(Exception): 9 | """ disguise a exception for cheat celery""" 10 | 11 | def __str__(self): 12 | return 'Start' 13 | 14 | 15 | class TimesValuesError(Exception): 16 | """check decorator params: max_times""" 17 | 18 | def __str__(self): 19 | return "params of tigger_task: max_times, isn't exist " 20 | 21 | 22 | def check_argument(**kwargs): 23 | countdown = kwargs.get('countdown', 1) # default 1 seconds 24 | max_times = kwargs.get('max_times') 25 | if not max_times: 26 | raise TimesValuesError() 27 | elif max_times == 'forever': 28 | 29 | """default 77777 times . 30 | Please be careful! if use, don't forget revoke it""" 31 | 32 | max_times = 77777 33 | elif not isinstance(max_times, int): 34 | raise TypeError("max_times must int type") 35 | 36 | return dict(countdown=countdown, max_times=max_times) 37 | -------------------------------------------------------------------------------- /celery_tasktigger/decorator.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 Boyle Gu 3 | # Licensed under The MIT License (MIT) 4 | # http://opensource.org/licenses/MIT 5 | # 6 | from __future__ import absolute_import, unicode_literals 7 | from functools import wraps 8 | 9 | from celery_tasktigger import LoopCaptureTag, check_argument 10 | 11 | 12 | def tigger_task(**tigger_kwargs): 13 | """ 14 | Fully compatible with Celery 15 | 16 | :param tigger_kwargs: countdown # Execute in x seconds (default 1 seconds ) 17 | :param tigger_kwargs: max_times # Max x times 18 | """ 19 | 20 | def _decorator(func): 21 | @wraps(func) 22 | def wrapper(self, *args, **kwargs): 23 | check_args = None 24 | try: 25 | countdown = kwargs.get('countdown') 26 | if countdown: 27 | tigger_kwargs.update({'countdown': countdown}) 28 | check_args = check_argument(**tigger_kwargs) 29 | func(self, *args, **kwargs) 30 | raise LoopCaptureTag() 31 | except LoopCaptureTag as exc: 32 | raise self.retry(exc=exc, countdown=check_args['countdown'], 33 | max_retries=check_args['max_times']) 34 | 35 | return wrapper 36 | 37 | return _decorator 38 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from celery import Celery 4 | 5 | from celery_tasktigger.decorator import tigger_task 6 | 7 | app = Celery('example', backend='amqp', broker='amqp://127.0.0.1:5672//') 8 | 9 | # upgrade celery 4.0 10 | app.conf.update( 11 | result_backend='amqp', 12 | result_expires=18000, # 5 hours. 13 | ) 14 | 15 | 16 | # celery -A example worker -l info 17 | @app.task(bind=True) 18 | @tigger_task(max_times='forever', countdown=3) 19 | def add(self, x, y): 20 | return x + y 21 | -------------------------------------------------------------------------------- /images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boylegu/celery-task-tigger/8951da61e6bebc17c7a3c4611695822a733608d2/images/logo.jpg -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | try: 3 | from setuptools import setup 4 | except ImportError: 5 | from distutils.core import setup 6 | 7 | 8 | __version_info__ = (0, 4) 9 | __version__ = '.'.join([str(v) for v in __version_info__]) 10 | 11 | with open(os.path.join(os.path.dirname(__file__), 'README.md')) as readme: 12 | README = readme.read() 13 | 14 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 15 | 16 | setup( 17 | name='celery-task-tigger', 18 | version=__version__, 19 | packages=['celery_tasktigger'], 20 | include_package_data=True, 21 | license='MIT License', 22 | description='A controllable timing task widgets with Celery.', 23 | long_description=README, 24 | url='https://github.com/boylegu/celery-task-tigger', 25 | author='BoyleGu', 26 | author_email='gubaoer@hotmail.com', 27 | classifiers=[ 28 | 'Development Status :: 5 - Production/Stable', 29 | 'Intended Audience :: Developers', 30 | 'License :: OSI Approved :: MIT License', 31 | 'Operating System :: OS Independent', 32 | 'Programming Language :: Python', 33 | 'Programming Language :: Python :: 2', 34 | 'Programming Language :: Python :: 2.7', 35 | 'Programming Language :: Python :: 3', 36 | 'Programming Language :: Python :: 3.4', 37 | 'Programming Language :: Python :: 3.5', 38 | 'Programming Language :: Python :: Implementation :: CPython', 39 | 'Topic :: Internet :: WWW/HTTP', 40 | 'Topic :: Software Development :: Libraries', 41 | ], 42 | ) 43 | --------------------------------------------------------------------------------