Skip to content

Commit

Permalink
[#111] Cancel the impossible future when approved and re-create the w…
Browse files Browse the repository at this point in the history
…hole rest of the workflow when it cycles
  • Loading branch information
javrasya committed Nov 17, 2019
1 parent 0577572 commit e8b2496
Show file tree
Hide file tree
Showing 3 changed files with 346 additions and 13 deletions.
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Change Logs
* **Improvement** - # 108_: Status column of transition approvals are now kept as string in the DB instead of number to maintain readability and avoid mistakenly changed ordinals.
* **Improvement** - # 109_: Cancel all other peer approvals that are with different branching state.
* **Improvement** - # 110_: Introduce an iteration to keep track of the order of the transitions even the cycling ones. This comes with a migration that will assess the iteration of all of your existing approvals so far. According to the tests, 250 workflow objects that have 5 approvals each will take ~1 minutes with the slowest django `v1.11`.
* **Improvement** - # 111_: Cancel all approvals that are not part of the possible future instead of only impossible the peers when something approved and re-create the whole rest of the pipeline when it cycles
* **Improvement** - # 105_: More dynamic and better way for hooks.On the fly function and hook creations, update or delete are also supported now. It also comes with useful admin interfaces for hooks and functions. This is a huge improvement for callback lovers :-)


Expand All @@ -19,6 +20,7 @@ Change Logs
.. _108: https://github.com/javrasya/django-river/issues/108
.. _109: https://github.com/javrasya/django-river/issues/109
.. _110: https://github.com/javrasya/django-river/issues/110
.. _111: https://github.com/javrasya/django-river/issues/110

2.0.0 (Stable)
--------------
Expand Down
55 changes: 50 additions & 5 deletions river/core/instanceworkflowobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import six
from django.contrib.contenttypes.models import ContentType
from django.db import transaction
from django.db.models import Q
from django.db.transaction import atomic
from django.utils import timezone

Expand Down Expand Up @@ -118,7 +119,7 @@ def approve(self, as_user, next_state=None):
approval.previous = self.recent_approval
approval.save()

approval.peers.filter(status=PENDING).exclude(destination_state=approval.destination_state).update(status=CANCELLED)
self.cancel_impossible_future(approval)

has_transit = False
if approval.peers.filter(status=PENDING).count() == 0:
Expand All @@ -133,6 +134,52 @@ def approve(self, as_user, next_state=None):
with self._approve_signal(approval), self._transition_signal(has_transit, approval), self._on_complete_signal():
self.workflow_object.save()

def cancel_impossible_future(self, approved_approval):
cancelled_approvals_qs = Q(pk=-1)
qs = Q(
workflow=self.workflow,
object_id=self.workflow_object.pk,
iteration=approved_approval.iteration,
source_state=approved_approval.source_state,
) & ~Q(destination_state=approved_approval.destination_state)

approvals = TransitionApproval.objects.filter(qs)
iteration = approved_approval.iteration + 1
while approvals:
cancelled_approvals_qs = cancelled_approvals_qs | qs
qs = Q(
workflow=self.workflow,
object_id=self.workflow_object.pk,
iteration=iteration,
source_state__pk__in=approvals.values_list("destination_state__pk", flat=True)
)
approvals = TransitionApproval.objects.filter(qs)
iteration += 1

uncancelled_approvals_qs = Q(pk=-1)
qs = Q(
workflow=self.workflow,
object_id=self.workflow_object.pk,
iteration=approved_approval.iteration,
source_state=approved_approval.source_state,
destination_state=approved_approval.destination_state
)
approvals = TransitionApproval.objects.filter(qs)
iteration = approved_approval.iteration + 1
while approvals:
uncancelled_approvals_qs = uncancelled_approvals_qs | qs
qs = Q(
workflow=self.workflow,
object_id=self.workflow_object.pk,
iteration=iteration,
source_state__pk__in=approvals.values_list("destination_state__pk", flat=True),
status=PENDING
)
approvals = TransitionApproval.objects.filter(qs)
iteration += 1

TransitionApproval.objects.filter(cancelled_approvals_qs & ~uncancelled_approvals_qs).update(status=CANCELLED)

def _approve_signal(self, approval):
return ApproveSignal(self.workflow_object, self.field_name, approval)

Expand All @@ -159,9 +206,8 @@ def _check_if_it_cycled(self, new_state):

def _re_create_cycled_path(self, from_state, last_iteration):
approvals = TransitionApproval.objects.filter(workflow_object=self.workflow_object, workflow=self.class_workflow.workflow, source_state=from_state)
cycle_ended = False
iteration = last_iteration + 1
while not cycle_ended:
while approvals:
for old_approval in approvals:
if old_approval.enabled:
cycled_approval = TransitionApproval.objects.create(
Expand All @@ -183,8 +229,7 @@ def _re_create_cycled_path(self, from_state, last_iteration):
workflow_object=self.workflow_object,
workflow=self.class_workflow.workflow,
source_state__in=approvals.values_list("destination_state", flat=TransitionApproval)
)
cycle_ended = approvals.filter(source_state=from_state).count() > 0
).exclude(source_state=from_state)
iteration += 1

def get_state(self):
Expand Down
Loading

0 comments on commit e8b2496

Please sign in to comment.