Skip to content
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

Task group #8332

Merged
merged 8 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/backend/InvenTree/InvenTree/helpers_email.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,5 @@ def send_email(subject, body, recipients, from_email=None, html_message=None):
recipients,
fail_silently=False,
html_message=html_message,
group='notification',
)
5 changes: 4 additions & 1 deletion src/backend/InvenTree/InvenTree/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ def offload_task(
"""
from InvenTree.exceptions import log_error

# Extract group information from kwargs
group = kwargs.pop('group', 'inventree')

try:
import importlib

Expand All @@ -200,7 +203,7 @@ def offload_task(
if force_async or (is_worker_running() and not force_sync):
# Running as asynchronous task
try:
task = AsyncTask(taskname, *args, **kwargs)
task = AsyncTask(taskname, *args, group=group, **kwargs)
task.run()
except ImportError:
raise_warning(f"WARNING: '{taskname}' not offloaded - Function not found")
Expand Down
12 changes: 9 additions & 3 deletions src/backend/InvenTree/build/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,8 @@ def _action_complete(self, *args, **kwargs):
if not InvenTree.tasks.offload_task(
build.tasks.complete_build_allocations,
self.pk,
user.pk if user else None
user.pk if user else None,
group='build'
):
raise ValidationError(_("Failed to offload task to complete build allocations"))

Expand Down Expand Up @@ -772,7 +773,8 @@ def _action_cancel(self, *args, **kwargs):
if not InvenTree.tasks.offload_task(
build.tasks.complete_build_allocations,
self.pk,
user.pk if user else None
user.pk if user else None,
group='build',
):
raise ValidationError(_("Failed to offload task to complete build allocations"))

Expand Down Expand Up @@ -1441,7 +1443,11 @@ def after_save_build(sender, instance: Build, created: bool, **kwargs):
instance.create_build_line_items()

# Run checks on required parts
InvenTree.tasks.offload_task(build_tasks.check_build_stock, instance)
InvenTree.tasks.offload_task(
build_tasks.check_build_stock,
instance,
group='build'
)

# Notify the responsible users that the build order has been created
InvenTree.helpers_model.notify_responsible(instance, sender, exclude=instance.issued_by)
Expand Down
4 changes: 3 additions & 1 deletion src/backend/InvenTree/build/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ def create(self, validated_data):
InvenTree.tasks.offload_task(
build.tasks.create_child_builds,
build_order.pk,
group='build',
)

return build_order
Expand Down Expand Up @@ -1134,7 +1135,8 @@ def save(self):
exclude_location=data.get('exclude_location', None),
interchangeable=data['interchangeable'],
substitutes=data['substitutes'],
optional_items=data['optional_items']
optional_items=data['optional_items'],
group='build'
):
raise ValidationError(_("Failed to start auto-allocation task"))

Expand Down
3 changes: 2 additions & 1 deletion src/backend/InvenTree/build/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ def create_child_builds(build_id: int) -> None:
# Offload the child build order creation to the background task queue
InvenTree.tasks.offload_task(
create_child_builds,
sub_order.pk
sub_order.pk,
group='build'
)


Expand Down
4 changes: 3 additions & 1 deletion src/backend/InvenTree/common/currency.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ def after_change_currency(setting) -> None:
InvenTree.tasks.update_exchange_rates(force=True)

# Offload update of part prices to a background task
InvenTree.tasks.offload_task(part_tasks.check_missing_pricing, force_async=True)
InvenTree.tasks.offload_task(
part_tasks.check_missing_pricing, force_async=True, group='pricing'
)


def validate_currency_codes(value):
Expand Down
1 change: 1 addition & 0 deletions src/backend/InvenTree/order/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1919,6 +1919,7 @@ def complete_shipment(self, user, **kwargs):
order.tasks.complete_sales_order_shipment,
shipment_id=self.pk,
user_id=user.pk if user else None,
group='sales_order',
)

trigger_event('salesordershipment.completed', id=self.pk)
Expand Down
22 changes: 17 additions & 5 deletions src/backend/InvenTree/part/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2560,15 +2560,21 @@ def after_save_part(sender, instance: Part, created, **kwargs):
# Run this check in the background
try:
InvenTree.tasks.offload_task(
part_tasks.notify_low_stock_if_required, instance
part_tasks.notify_low_stock_if_required,
instance.pk,
group='notification',
force_async=True,
)
except PicklingError:
# Can sometimes occur if the referenced Part has issues
pass
log_error('after_save_part')

# Schedule a background task to rebuild any supplier parts
InvenTree.tasks.offload_task(
part_tasks.rebuild_supplier_parts, instance.pk, force_async=True
part_tasks.rebuild_supplier_parts,
instance.pk,
force_async=True,
group='part',
)


Expand Down Expand Up @@ -2705,6 +2711,7 @@ def schedule_for_update(self, counter: int = 0):
self,
counter=counter,
force_async=background,
group='pricing',
)

def update_pricing(
Expand Down Expand Up @@ -3856,7 +3863,10 @@ def post_save_part_parameter_template(sender, instance, created, **kwargs):
if not created:
# Schedule a background task to rebuild the parameters against this template
InvenTree.tasks.offload_task(
part_tasks.rebuild_parameters, instance.pk, force_async=True
part_tasks.rebuild_parameters,
instance.pk,
force_async=True,
group='part',
)


Expand Down Expand Up @@ -4548,7 +4558,9 @@ def update_bom_build_lines(sender, instance, created, **kwargs):
if InvenTree.ready.canAppAccessDatabase() and not InvenTree.ready.isImportingData():
import build.tasks

InvenTree.tasks.offload_task(build.tasks.update_build_order_lines, instance.pk)
InvenTree.tasks.offload_task(
build.tasks.update_build_order_lines, instance.pk, group='build'
)


@receiver(post_save, sender=BomItem, dispatch_uid='post_save_bom_item')
Expand Down
1 change: 1 addition & 0 deletions src/backend/InvenTree/part/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,7 @@ def save(self):
exclude_external=data.get('exclude_external', True),
generate_report=data.get('generate_report', True),
update_parts=data.get('update_parts', True),
group='report',
)


Expand Down
38 changes: 23 additions & 15 deletions src/backend/InvenTree/part/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import InvenTree.helpers
import InvenTree.helpers_model
import InvenTree.tasks
import part.models
import part.models as part_models
import part.stocktake
from common.settings import get_global_setting
from InvenTree.tasks import (
Expand All @@ -27,7 +27,7 @@
logger = logging.getLogger('inventree')


def notify_low_stock(part: part.models.Part):
def notify_low_stock(part: part_models.Part):
"""Notify interested users that a part is 'low stock'.

Rules:
Expand All @@ -51,20 +51,28 @@ def notify_low_stock(part: part.models.Part):
)


def notify_low_stock_if_required(part: part.models.Part):
def notify_low_stock_if_required(part_id: int):
"""Check if the stock quantity has fallen below the minimum threshold of part.

If true, notify the users who have subscribed to the part
"""
try:
part = part_models.Part.objects.get(pk=part_id)
except part_models.Part.DoesNotExist:
logger.warning(
'notify_low_stock_if_required: Part with ID %s does not exist', part_id
)
return

# Run "up" the tree, to allow notification for "parent" parts
parts = part.get_ancestors(include_self=True, ascending=True)

for p in parts:
if p.is_part_low_on_stock():
InvenTree.tasks.offload_task(notify_low_stock, p)
InvenTree.tasks.offload_task(notify_low_stock, p, group='notification')


def update_part_pricing(pricing: part.models.PartPricing, counter: int = 0):
def update_part_pricing(pricing: part_models.PartPricing, counter: int = 0):
"""Update cached pricing data for the specified PartPricing instance.

Arguments:
Expand Down Expand Up @@ -93,7 +101,7 @@ def check_missing_pricing(limit=250):
limit: Maximum number of parts to process at once
"""
# Find parts for which pricing information has never been updated
results = part.models.PartPricing.objects.filter(updated=None)[:limit]
results = part_models.PartPricing.objects.filter(updated=None)[:limit]

if results.count() > 0:
logger.info('Found %s parts with empty pricing', results.count())
Expand All @@ -105,7 +113,7 @@ def check_missing_pricing(limit=250):
days = int(get_global_setting('PRICING_UPDATE_DAYS', 30))
stale_date = datetime.now().date() - timedelta(days=days)

results = part.models.PartPricing.objects.filter(updated__lte=stale_date)[:limit]
results = part_models.PartPricing.objects.filter(updated__lte=stale_date)[:limit]

if results.count() > 0:
logger.info('Found %s stale pricing entries', results.count())
Expand All @@ -115,7 +123,7 @@ def check_missing_pricing(limit=250):

# Find any pricing data which is in the wrong currency
currency = common.currency.currency_code_default()
results = part.models.PartPricing.objects.exclude(currency=currency)
results = part_models.PartPricing.objects.exclude(currency=currency)

if results.count() > 0:
logger.info('Found %s pricing entries in the wrong currency', results.count())
Expand All @@ -124,7 +132,7 @@ def check_missing_pricing(limit=250):
pp.schedule_for_update()

# Find any parts which do not have pricing information
results = part.models.Part.objects.filter(pricing_data=None)[:limit]
results = part_models.Part.objects.filter(pricing_data=None)[:limit]

if results.count() > 0:
logger.info('Found %s parts without pricing', results.count())
Expand Down Expand Up @@ -152,7 +160,7 @@ def scheduled_stocktake_reports():
get_global_setting('STOCKTAKE_DELETE_REPORT_DAYS', 30, cache=False)
)
threshold = datetime.now() - timedelta(days=delete_n_days)
old_reports = part.models.PartStocktakeReport.objects.filter(date__lt=threshold)
old_reports = part_models.PartStocktakeReport.objects.filter(date__lt=threshold)

if old_reports.count() > 0:
logger.info('Deleting %s stale stocktake reports', old_reports.count())
Expand Down Expand Up @@ -187,11 +195,11 @@ def rebuild_parameters(template_id):
which may cause the base unit to be adjusted.
"""
try:
template = part.models.PartParameterTemplate.objects.get(pk=template_id)
except part.models.PartParameterTemplate.DoesNotExist:
template = part_models.PartParameterTemplate.objects.get(pk=template_id)
except part_models.PartParameterTemplate.DoesNotExist:
return

parameters = part.models.PartParameter.objects.filter(template=template)
parameters = part_models.PartParameter.objects.filter(template=template)

n = 0

Expand All @@ -216,8 +224,8 @@ def rebuild_supplier_parts(part_id):
which may cause the native units of any supplier parts to be updated
"""
try:
prt = part.models.Part.objects.get(pk=part_id)
except part.models.Part.DoesNotExist:
prt = part_models.Part.objects.get(pk=part_id)
except part_models.Part.DoesNotExist:
return

supplier_parts = company.models.SupplierPart.objects.filter(part=prt)
Expand Down
6 changes: 4 additions & 2 deletions src/backend/InvenTree/plugin/base/event/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def trigger_event(event, *args, **kwargs):
if 'force_async' not in kwargs and not settings.PLUGIN_TESTING_EVENTS:
kwargs['force_async'] = True

offload_task(register_event, event, *args, **kwargs)
offload_task(register_event, event, *args, group='plugin', **kwargs)


def register_event(event, *args, **kwargs):
Expand Down Expand Up @@ -77,7 +77,9 @@ def register_event(event, *args, **kwargs):
kwargs['force_async'] = True

# Offload a separate task for each plugin
offload_task(process_event, slug, event, *args, **kwargs)
offload_task(
process_event, slug, event, *args, group='plugin', **kwargs
)


def process_event(plugin_slug, event, *args, **kwargs):
Expand Down
7 changes: 6 additions & 1 deletion src/backend/InvenTree/plugin/base/label/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,12 @@ def print_labels(
# Exclude the 'context' object - cannot be pickled
print_args.pop('context', None)

offload_task(plugin_label.print_label, self.plugin_slug(), **print_args)
offload_task(
plugin_label.print_label,
self.plugin_slug(),
group='plugin',
**print_args,
)

# Update the progress of the print job
output.progress += int(100 / N)
Expand Down
7 changes: 6 additions & 1 deletion src/backend/InvenTree/plugin/base/locate/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ def post(self, request, *args, **kwargs):
StockItem.objects.get(pk=item_pk)

offload_task(
registry.call_plugin_function, plugin, 'locate_stock_item', item_pk
registry.call_plugin_function,
plugin,
'locate_stock_item',
item_pk,
group='plugin',
)

data['item'] = item_pk
Expand All @@ -78,6 +82,7 @@ def post(self, request, *args, **kwargs):
plugin,
'locate_stock_location',
location_pk,
group='plugin',
)

data['location'] = location_pk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ def print_labels(self, label: LabelTemplate, output, items, request, **kwargs):
if driver.USE_BACKGROUND_WORKER is False:
return driver.print_labels(machine, label, items, **print_kwargs)

offload_task(driver.print_labels, machine, label, items, **print_kwargs)
offload_task(
driver.print_labels, machine, label, items, group='plugin', **print_kwargs
)

return JsonResponse({
'success': True,
Expand Down
4 changes: 3 additions & 1 deletion src/backend/InvenTree/plugin/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ def activate(self, active: bool) -> None:

if active:
offload_task(check_for_migrations)
offload_task(plugin.staticfiles.copy_plugin_static_files, self.key)
offload_task(
plugin.staticfiles.copy_plugin_static_files, self.key, group='plugin'
)


class PluginSetting(common.models.BaseInvenTreeSetting):
Expand Down
Loading
Loading