mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
[Bug] Fix for create_child_builds (#8399)
* Fix for create_child_builds - Account for concurrency between multiple worker processes - Ensure db commits are atomic - Add random delays between build creation * Check for existing build order * Initially force task off to background worker * Revert force_async change
This commit is contained in:
parent
feefa60a8f
commit
913a05cf45
@ -180,6 +180,7 @@ class BuildSerializer(NotesFieldMixin, DataImportExportSerializerMixin, InvenTre
|
|||||||
|
|
||||||
return reference
|
return reference
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
"""Save the Build object."""
|
"""Save the Build object."""
|
||||||
|
|
||||||
@ -192,7 +193,7 @@ class BuildSerializer(NotesFieldMixin, DataImportExportSerializerMixin, InvenTre
|
|||||||
InvenTree.tasks.offload_task(
|
InvenTree.tasks.offload_task(
|
||||||
build.tasks.create_child_builds,
|
build.tasks.create_child_builds,
|
||||||
build_order.pk,
|
build_order.pk,
|
||||||
group='build',
|
group='build'
|
||||||
)
|
)
|
||||||
|
|
||||||
return build_order
|
return build_order
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
"""Background task definitions for the BuildOrder app."""
|
"""Background task definitions for the BuildOrder app."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
from django.db import transaction
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allauth.account.models import EmailAddress
|
from allauth.account.models import EmailAddress
|
||||||
@ -198,9 +202,28 @@ def create_child_builds(build_id: int) -> None:
|
|||||||
|
|
||||||
assembly_items = build_order.part.get_bom_items().filter(sub_part__assembly=True)
|
assembly_items = build_order.part.get_bom_items().filter(sub_part__assembly=True)
|
||||||
|
|
||||||
|
# Random delay, to reduce likelihood of race conditions from multiple build orders being created simultaneously
|
||||||
|
time.sleep(random.random())
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
# Atomic transaction to ensure that all child build orders are created together, or not at all
|
||||||
|
# This is critical to prevent duplicate child build orders being created (e.g. if the task is re-run)
|
||||||
|
|
||||||
|
sub_build_ids = []
|
||||||
|
|
||||||
for item in assembly_items:
|
for item in assembly_items:
|
||||||
quantity = item.quantity * build_order.quantity
|
quantity = item.quantity * build_order.quantity
|
||||||
|
|
||||||
|
|
||||||
|
# Check if the child build order has already been created
|
||||||
|
if build_models.Build.objects.filter(
|
||||||
|
part=item.sub_part,
|
||||||
|
parent=build_order,
|
||||||
|
quantity=quantity,
|
||||||
|
status__in=BuildStatusGroups.ACTIVE_CODES
|
||||||
|
).exists():
|
||||||
|
continue
|
||||||
|
|
||||||
sub_order = build_models.Build.objects.create(
|
sub_order = build_models.Build.objects.create(
|
||||||
part=item.sub_part,
|
part=item.sub_part,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
@ -213,10 +236,13 @@ def create_child_builds(build_id: int) -> None:
|
|||||||
responsible=build_order.responsible,
|
responsible=build_order.responsible,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
sub_build_ids.append(sub_order.pk)
|
||||||
|
|
||||||
|
for pk in sub_build_ids:
|
||||||
# Offload the child build order creation to the background task queue
|
# Offload the child build order creation to the background task queue
|
||||||
InvenTree.tasks.offload_task(
|
InvenTree.tasks.offload_task(
|
||||||
create_child_builds,
|
create_child_builds,
|
||||||
sub_order.pk,
|
pk,
|
||||||
group='build'
|
group='build'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user