mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-29 12:06:44 +00:00
Switch to registry for tasks (#3790)
* Add general registering functions Fixes #3787 * switch over to new method * move to static type * fix unclear naming
This commit is contained in:
parent
182bc29053
commit
0bea2c7b56
@ -54,68 +54,16 @@ class InvenTreeConfig(AppConfig):
|
|||||||
|
|
||||||
def start_background_tasks(self):
|
def start_background_tasks(self):
|
||||||
"""Start all background tests for InvenTree."""
|
"""Start all background tests for InvenTree."""
|
||||||
try:
|
|
||||||
from django_q.models import Schedule
|
|
||||||
except AppRegistryNotReady: # pragma: no cover
|
|
||||||
logger.warning("Cannot start background tasks - app registry not ready")
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info("Starting background tasks...")
|
logger.info("Starting background tasks...")
|
||||||
|
# Run through registered tasks
|
||||||
# Remove successful task results from the database
|
for task in InvenTree.tasks.tasks.task_list:
|
||||||
InvenTree.tasks.schedule_task(
|
InvenTree.tasks.schedule_task(
|
||||||
'InvenTree.tasks.delete_successful_tasks',
|
task.func,
|
||||||
schedule_type=Schedule.DAILY,
|
schedule_type=task.interval,
|
||||||
)
|
minutes=task.minutes,
|
||||||
|
|
||||||
# Check for InvenTree updates
|
|
||||||
InvenTree.tasks.schedule_task(
|
|
||||||
'InvenTree.tasks.check_for_updates',
|
|
||||||
schedule_type=Schedule.DAILY
|
|
||||||
)
|
|
||||||
|
|
||||||
# Heartbeat to let the server know the background worker is running
|
|
||||||
InvenTree.tasks.schedule_task(
|
|
||||||
'InvenTree.tasks.heartbeat',
|
|
||||||
schedule_type=Schedule.MINUTES,
|
|
||||||
minutes=15
|
|
||||||
)
|
|
||||||
|
|
||||||
# Keep exchange rates up to date
|
|
||||||
InvenTree.tasks.schedule_task(
|
|
||||||
'InvenTree.tasks.update_exchange_rates',
|
|
||||||
schedule_type=Schedule.DAILY,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Delete old error messages
|
|
||||||
InvenTree.tasks.schedule_task(
|
|
||||||
'InvenTree.tasks.delete_old_error_logs',
|
|
||||||
schedule_type=Schedule.DAILY,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Delete old notification records
|
|
||||||
InvenTree.tasks.schedule_task(
|
|
||||||
'common.tasks.delete_old_notifications',
|
|
||||||
schedule_type=Schedule.DAILY,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check for overdue purchase orders
|
|
||||||
InvenTree.tasks.schedule_task(
|
|
||||||
'order.tasks.check_overdue_purchase_orders',
|
|
||||||
schedule_type=Schedule.DAILY
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check for overdue sales orders
|
|
||||||
InvenTree.tasks.schedule_task(
|
|
||||||
'order.tasks.check_overdue_sales_orders',
|
|
||||||
schedule_type=Schedule.DAILY,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check for overdue build orders
|
|
||||||
InvenTree.tasks.schedule_task(
|
|
||||||
'build.tasks.check_overdue_build_orders',
|
|
||||||
schedule_type=Schedule.DAILY
|
|
||||||
)
|
)
|
||||||
|
logger.info("Started background tasks...")
|
||||||
|
|
||||||
# Make regular backups
|
# Make regular backups
|
||||||
InvenTree.tasks.schedule_task(
|
InvenTree.tasks.schedule_task(
|
||||||
|
@ -4,7 +4,9 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import mail as django_mail
|
from django.core import mail as django_mail
|
||||||
@ -126,6 +128,69 @@ def offload_task(taskname, *args, force_async=False, force_sync=False, **kwargs)
|
|||||||
_func(*args, **kwargs)
|
_func(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass()
|
||||||
|
class ScheduledTask:
|
||||||
|
"""A scheduled task.
|
||||||
|
|
||||||
|
- interval: The interval at which the task should be run
|
||||||
|
- minutes: The number of minutes between task runs
|
||||||
|
- func: The function to be run
|
||||||
|
"""
|
||||||
|
|
||||||
|
func: Callable
|
||||||
|
interval: str
|
||||||
|
minutes: int = None
|
||||||
|
|
||||||
|
MINUTES = "I"
|
||||||
|
HOURLY = "H"
|
||||||
|
DAILY = "D"
|
||||||
|
WEEKLY = "W"
|
||||||
|
MONTHLY = "M"
|
||||||
|
QUARTERLY = "Q"
|
||||||
|
YEARLY = "Y"
|
||||||
|
TYPE = [MINUTES, HOURLY, DAILY, WEEKLY, MONTHLY, QUARTERLY, YEARLY]
|
||||||
|
|
||||||
|
|
||||||
|
class TaskRegister:
|
||||||
|
"""Registery for periodicall tasks."""
|
||||||
|
task_list: list[ScheduledTask] = []
|
||||||
|
|
||||||
|
def register(self, task, schedule, minutes: int = None):
|
||||||
|
"""Register a task with the que."""
|
||||||
|
self.task_list.append(ScheduledTask(task, schedule, minutes))
|
||||||
|
|
||||||
|
|
||||||
|
tasks = TaskRegister()
|
||||||
|
|
||||||
|
|
||||||
|
def scheduled_task(interval: str, minutes: int = None):
|
||||||
|
"""Register the given task as a scheduled task.
|
||||||
|
|
||||||
|
- interval: The interval at which the task should be run
|
||||||
|
- minutes: The number of minutes between task runs
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
@register(ScheduledTask.DAILY)
|
||||||
|
def my_custom_funciton():
|
||||||
|
...
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _task_wrapper(admin_class):
|
||||||
|
if not isinstance(admin_class, Callable):
|
||||||
|
raise ValueError('Wrapped object must be a function')
|
||||||
|
|
||||||
|
if interval not in ScheduledTask.TYPE:
|
||||||
|
raise ValueError(f'Invalid interval. Must be one of {ScheduledTask.TYPE}')
|
||||||
|
|
||||||
|
tasks.register(admin_class, interval, minutes=minutes)
|
||||||
|
|
||||||
|
return admin_class
|
||||||
|
return _task_wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@scheduled_task(ScheduledTask.MINUTES, 15)
|
||||||
def heartbeat():
|
def heartbeat():
|
||||||
"""Simple task which runs at 5 minute intervals, so we can determine that the background worker is actually running.
|
"""Simple task which runs at 5 minute intervals, so we can determine that the background worker is actually running.
|
||||||
|
|
||||||
@ -149,6 +214,7 @@ def heartbeat():
|
|||||||
heartbeats.delete()
|
heartbeats.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@scheduled_task(ScheduledTask.DAILY)
|
||||||
def delete_successful_tasks():
|
def delete_successful_tasks():
|
||||||
"""Delete successful task logs which are more than a month old."""
|
"""Delete successful task logs which are more than a month old."""
|
||||||
try:
|
try:
|
||||||
@ -168,6 +234,7 @@ def delete_successful_tasks():
|
|||||||
results.delete()
|
results.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@scheduled_task(ScheduledTask.DAILY)
|
||||||
def delete_old_error_logs():
|
def delete_old_error_logs():
|
||||||
"""Delete old error logs from the server."""
|
"""Delete old error logs from the server."""
|
||||||
try:
|
try:
|
||||||
@ -190,6 +257,7 @@ def delete_old_error_logs():
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@scheduled_task(ScheduledTask.DAILY)
|
||||||
def check_for_updates():
|
def check_for_updates():
|
||||||
"""Check if there is an update for InvenTree."""
|
"""Check if there is an update for InvenTree."""
|
||||||
try:
|
try:
|
||||||
@ -232,6 +300,7 @@ def check_for_updates():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@scheduled_task(ScheduledTask.DAILY)
|
||||||
def update_exchange_rates():
|
def update_exchange_rates():
|
||||||
"""Update currency exchange rates."""
|
"""Update currency exchange rates."""
|
||||||
try:
|
try:
|
||||||
|
@ -144,6 +144,7 @@ def notify_overdue_build_order(bo: build.models.Build):
|
|||||||
trigger_event(event_name, build_order=bo.pk)
|
trigger_event(event_name, build_order=bo.pk)
|
||||||
|
|
||||||
|
|
||||||
|
@InvenTree.tasks.scheduled_task(InvenTree.tasks.ScheduledTask.DAILY)
|
||||||
def check_overdue_build_orders():
|
def check_overdue_build_orders():
|
||||||
"""Check if any outstanding BuildOrders have just become overdue
|
"""Check if any outstanding BuildOrders have just become overdue
|
||||||
|
|
||||||
|
@ -5,9 +5,12 @@ from datetime import datetime, timedelta
|
|||||||
|
|
||||||
from django.core.exceptions import AppRegistryNotReady
|
from django.core.exceptions import AppRegistryNotReady
|
||||||
|
|
||||||
|
from InvenTree.tasks import ScheduledTask, scheduled_task
|
||||||
|
|
||||||
logger = logging.getLogger('inventree')
|
logger = logging.getLogger('inventree')
|
||||||
|
|
||||||
|
|
||||||
|
@scheduled_task(ScheduledTask.DAILY)
|
||||||
def delete_old_notifications():
|
def delete_old_notifications():
|
||||||
"""Remove old notifications from the database.
|
"""Remove old notifications from the database.
|
||||||
|
|
||||||
|
@ -6,12 +6,13 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
import common.notifications
|
import common.notifications
|
||||||
import InvenTree.helpers
|
import InvenTree.helpers
|
||||||
import InvenTree.tasks
|
|
||||||
import order.models
|
import order.models
|
||||||
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
||||||
|
from InvenTree.tasks import ScheduledTask, scheduled_task
|
||||||
from plugin.events import trigger_event
|
from plugin.events import trigger_event
|
||||||
|
|
||||||
|
|
||||||
|
@scheduled_task(ScheduledTask.DAILY)
|
||||||
def notify_overdue_purchase_order(po: order.models.PurchaseOrder):
|
def notify_overdue_purchase_order(po: order.models.PurchaseOrder):
|
||||||
"""Notify users that a PurchaseOrder has just become 'overdue'"""
|
"""Notify users that a PurchaseOrder has just become 'overdue'"""
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ def notify_overdue_purchase_order(po: order.models.PurchaseOrder):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@scheduled_task(ScheduledTask.DAILY)
|
||||||
def check_overdue_purchase_orders():
|
def check_overdue_purchase_orders():
|
||||||
"""Check if any outstanding PurchaseOrders have just become overdue:
|
"""Check if any outstanding PurchaseOrders have just become overdue:
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user