-
-
Notifications
You must be signed in to change notification settings - Fork 683
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
Django q #1398
Django q #1398
Changes from 16 commits
7bec3ff
45b3c68
660fed9
5b68d82
1532a0c
3cf5aec
18defcf
4925f24
bfb0cb3
5b8eb1c
006dd10
ef4dbda
51616c8
9d404af
18b559f
700effc
de85d61
f6dd710
6ea846c
24823ad
c1aed51
c6e154f
2836636
b7718d9
8fd666e
edbbfff
e3f49b8
ce64feb
df0ab23
3a0c68b
3ddbb6a
39b2c5f
e7ed4c4
83f8afe
731ec25
3f25727
c0a0ca4
ab57fd3
1a7b6e2
6017cad
2746396
58bfc80
601aff8
42b400e
1f881dd
61f8b98
251ec7a
24d36e0
286cf9b
8b227ce
ff6b127
7683cc1
b9f9b26
b9e81c3
38b9655
76ab38a
08a1a6c
d446f8d
839c291
148600a
db858b3
47ba059
8e7e360
be41be3
8d3b9e2
2436b1f
00c4519
d915317
4a3ca46
9c38d67
d4d9263
14aead0
ed304f5
71cac6e
3926276
3381945
47a93bc
8eb571b
1372343
9086c8a
5e54b0f
e787c85
178715c
823f84e
2f1db48
91b6f98
5d9e273
8f626d3
5a168ab
3da5505
b74d365
0e1b647
c9021fe
2e8d3b6
78bcbe2
f6f3815
44fe572
5f9236d
f9449da
b490c5d
8f07efa
c2f85b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
import logging | ||
|
||
from django.apps import AppConfig | ||
from django.core.exceptions import AppRegistryNotReady | ||
|
||
import InvenTree.tasks | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class InvenTreeConfig(AppConfig): | ||
name = 'InvenTree' | ||
|
||
def ready(self): | ||
|
||
self.start_background_tasks() | ||
|
||
def start_background_tasks(self): | ||
|
||
try: | ||
from django_q.models import Schedule | ||
except (AppRegistryNotReady): | ||
return | ||
|
||
logger.info("Starting background tasks...") | ||
|
||
InvenTree.tasks.schedule_task( | ||
'InvenTree.tasks.delete_successful_tasks', | ||
schedule_type=Schedule.WEEKLY, | ||
) | ||
|
||
InvenTree.tasks.schedule_task( | ||
'InvenTree.tasks.check_for_updates', | ||
schedule_type=Schedule.DAILY | ||
) | ||
|
||
InvenTree.tasks.schedule_task( | ||
'InvenTree.tasks.heartbeat', | ||
schedule_type=Schedule.MINUTES, | ||
minutes=5 | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,49 @@ | ||
""" | ||
Provides system status functionality checks. | ||
""" | ||
# -*- coding: utf-8 -*- | ||
|
||
from django.utils.translation import ugettext as _ | ||
from __future__ import unicode_literals | ||
|
||
import logging | ||
from datetime import datetime, timedelta | ||
|
||
from django.utils.translation import ugettext as _ | ||
|
||
from django_q.models import Success | ||
from django_q.monitor import Stat | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def is_q_cluster_running(**kwargs): | ||
""" | ||
Return True if at least one cluster worker is running | ||
""" | ||
|
||
clusters = Stat.get_all() | ||
|
||
if len(clusters) > 0: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if clusters: Since it's more pythonic. Or if stat.get_all(): return True |
||
return True | ||
|
||
""" | ||
Sometimes Stat.get_all() returns []. | ||
In this case we have the 'heartbeat' task running every five minutes. | ||
Check to see if we have a result within the last ten minutes | ||
""" | ||
|
||
now = datetime.now() | ||
past = now - timedelta(minutes=10) | ||
|
||
results = Success.objects.filter( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would just delete any heart beat other than the last one while I'm in this code. |
||
func='InvenTree.tasks.heartbeat', | ||
started__gte=past | ||
) | ||
|
||
# If any results are returned, then the background worker is running! | ||
return results.exists() | ||
|
||
|
||
def check_system_health(**kwargs): | ||
""" | ||
Check that the InvenTree system is running OK. | ||
|
@@ -19,21 +53,11 @@ def check_system_health(**kwargs): | |
|
||
result = True | ||
|
||
if not check_celery_worker(**kwargs): | ||
if not is_q_cluster_running(**kwargs): | ||
result = False | ||
logger.warning(_("Celery worker check failed")) | ||
logger.warning(_("Background worker check failed")) | ||
|
||
if not result: | ||
logger.warning(_("InvenTree system health checks failed")) | ||
|
||
return result | ||
|
||
|
||
def check_celery_worker(**kwargs): | ||
""" | ||
Check that a celery worker is running. | ||
""" | ||
|
||
# TODO - Checks that the configured celery worker thing is running | ||
|
||
return True |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import unicode_literals | ||
|
||
import re | ||
import json | ||
import requests | ||
import logging | ||
|
||
from datetime import datetime, timedelta | ||
|
||
from django.core.exceptions import AppRegistryNotReady | ||
from django.db.utils import OperationalError, ProgrammingError | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def schedule_task(taskname, **kwargs): | ||
""" | ||
Create a scheduled task. | ||
If the task has already been scheduled, ignore! | ||
""" | ||
|
||
try: | ||
from django_q.models import Schedule | ||
except (AppRegistryNotReady): | ||
logger.warning("Could not start background tasks - App registry not ready") | ||
return | ||
|
||
try: | ||
if Schedule.objects.filter(func=taskname).exists(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So what happens when the task parameters change? Like you want to shift the period from 5 minutes to 30 minutes say? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. Code has been updated now. |
||
logger.info(f"Scheduled task '{taskname}' already exists. (Skipping)") | ||
else: | ||
logger.info(f"Creating scheduled task '{taskname}'") | ||
|
||
Schedule.objects.create( | ||
func=taskname, | ||
**kwargs | ||
) | ||
except (OperationalError, ProgrammingError): | ||
# Required if the DB is not ready yet | ||
pass | ||
|
||
|
||
def heartbeat(): | ||
""" | ||
Simple task which runs at 5 minute intervals, | ||
so we can determine that the background worker | ||
is actually running. | ||
|
||
(There is probably a less "hacky" way of achieving this) | ||
""" | ||
pass | ||
|
||
|
||
def delete_successful_tasks(): | ||
""" | ||
Delete successful task logs | ||
which are more than a month old. | ||
""" | ||
|
||
threshold = datetime.now() - timedelta(days=30) | ||
|
||
results = Success.objects.filter( | ||
started__lte=threshold | ||
) | ||
|
||
results.delete() | ||
|
||
|
||
def check_for_updates(): | ||
""" | ||
Check if there is an update for InvenTree | ||
""" | ||
|
||
try: | ||
import common.models | ||
except AppRegistryNotReady: | ||
return | ||
|
||
response = requests.get('https://api.github.com/repos/inventree/inventree/releases/latest') | ||
|
||
if not response.status_code == 200: | ||
logger.warning(f'Unexpected status code from GitHub API: {response.status_code}') | ||
return | ||
|
||
data = json.loads(response.text) | ||
|
||
tag = data.get('tag_name', None) | ||
|
||
if not tag: | ||
logger.warning("'tag_name' missing from GitHub response") | ||
return | ||
|
||
match = re.match(r"^.*(\d+)\.(\d+)\.(\d+).*$", tag) | ||
|
||
if not len(match.groups()) == 3: | ||
logger.warning(f"Version '{tag}' did not match expected pattern") | ||
return | ||
|
||
try: | ||
latest_version = [int(x) for x in match.groups()] | ||
except (ValueError): | ||
logger.warning(f"Version '{tag}' not integer format") | ||
return | ||
|
||
if not len(latest_version) == 3: | ||
logger.warning(f"Version '{tag}' is not correct format") | ||
return | ||
|
||
logger.info(f"Latest InvenTree version: '{tag}'") | ||
|
||
# Save the version to the database | ||
common.models.InvenTreeSetting.set_setting( | ||
'INVENTREE_LATEST_VERSION', | ||
tag, | ||
None | ||
) |
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.
all_healthy = all([v for v in status.values()])