Skip to content

Commit

Permalink
Limit async transition to one at a time for object (#2644)
Browse files Browse the repository at this point in the history
* Limit async transition to one at a time for object
  • Loading branch information
mkurek authored and szok committed Aug 3, 2016
1 parent b6a9358 commit 954c071
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/ralph/lib/transitions/async.py
Expand Up @@ -58,7 +58,7 @@ def run_async_transition(job_id):
def _perform_async_transition(transition_job):
transition = transition_job.transition
obj = transition_job.obj
_check_instances_for_transition([obj], transition)
_check_instances_for_transition([obj], transition, check_async_job=False)
_check_action_with_instances([obj], transition)

# check if this job isn't already finished
Expand Down
22 changes: 20 additions & 2 deletions src/ralph/lib/transitions/models.py
Expand Up @@ -31,7 +31,7 @@
get_field_by_relation_path
)
from ralph.attachments.models import Attachment
from ralph.lib.external_services.models import Job
from ralph.lib.external_services.models import Job, JobStatus
from ralph.lib.mixins.models import TimeStampMixin
from ralph.lib.transitions.conf import (
DEFAULT_ASYNC_TRANSITION_SERVICE_NAME,
Expand Down Expand Up @@ -147,7 +147,9 @@ def _check_and_get_transition(obj, transition, field):
return transition


def _check_instances_for_transition(instances, transition):
def _check_instances_for_transition(
instances, transition, check_async_job=True
):
"""Check in respect of the instances source status.
Args:
Expand All @@ -169,6 +171,22 @@ def _check_instances_for_transition(instances, transition):
for instance, error_details in error.items():
errors[instance].append(error_details)

if transition.is_async and check_async_job:
for instance in instances:
if TransitionJob.objects.filter(
object_id=instance.id,
content_type=ContentType.objects.get_for_model(instance),
status__in=(JobStatus.STARTED, JobStatus.QUEUED)
).exists():
logger.warning(
'Another async transition is already running for {}'.format(
instance,
)
)
errors[instance].append(
'Another async transition for this object is already stared'
)

if errors:
raise TransitionNotAllowedError(
'Transition {} is not allowed for objects'.format(transition.name),
Expand Down
34 changes: 33 additions & 1 deletion src/ralph/lib/transitions/tests/test_actions.py
Expand Up @@ -14,7 +14,11 @@
OfficeInfrastructureFactory,
WarehouseFactory
)
from ralph.lib.transitions.models import TransitionsHistory
from ralph.lib.transitions.models import (
JobStatus,
TransitionJob,
TransitionsHistory
)
from ralph.lib.transitions.tests import TransitionTestCase
from ralph.licences.tests.factories import LicenceFactory

Expand Down Expand Up @@ -198,6 +202,34 @@ def test_async_gui(self):
history = self.get_transition_history(bo.pk)
self.assertIn(self.user.username, history.kwargs['user'])

def test_async_gui_running_new_when_another_in_progress_should_return_error(self): # noqa
# mock another async job running
TransitionJob.objects.create(
obj=self.bo,
transition=self.transition_2,
status=JobStatus.STARTED,
service_name='ASYNC',
)
request = self.client.post(
reverse(
'admin:back_office_backofficeasset_transition',
args=(self.bo.id, self.transition_2.id)
),
self.prepare_gui_data(),
follow=True
)
self.assertTrue(
request.redirect_chain[0][0],
reverse(
'admin:back_office_backofficeasset_change',
args=(self.bo.id,)
)
)
self.assertIn(
'Another async transition for this object is already stared',
str(list(request.context['messages'])[1])
)

def test_api_options(self):
request = self.api_client.options(
reverse(
Expand Down

0 comments on commit 954c071

Please sign in to comment.