def _process_timeouts(self):
        timeout_candidates = []

        # workflow execution timeout
        timeout_candidates.append(self.first_timeout())

        # decision tasks timeouts
        for task in self.decision_tasks:
            timeout_candidates.append(task.first_timeout())

        # activity tasks timeouts
        for task in self.activity_tasks:
            timeout_candidates.append(task.first_timeout())

        # remove blank values (foo.first_timeout() is a Timeout or None)
        timeout_candidates = list(filter(None, timeout_candidates))

        # now find the first timeout to process
        first_timeout = None
        if timeout_candidates:
            first_timeout = min(
                timeout_candidates,
                key=lambda t: t.timestamp
            )

        if first_timeout:
            should_schedule_decision_next = False
            if isinstance(first_timeout.obj, WorkflowExecution):
                self.timeout(first_timeout)
            elif isinstance(first_timeout.obj, DecisionTask):
                self.timeout_decision_task(first_timeout)
                should_schedule_decision_next = True
            elif isinstance(first_timeout.obj, ActivityTask):
                self.timeout_activity_task(first_timeout)
                should_schedule_decision_next = True
            else:
                raise NotImplementedError("Unhandled timeout object")

            # schedule decision task if needed
            if should_schedule_decision_next:
                self.schedule_decision_task()

            # the workflow execution progressed, let's see if another
            # timeout should be processed
            self._process_timeouts()
Backward clustering, using all the results of the query as
dataset/ETHPy150Open spulec/moto/moto/swf/models/workflow_execution.py/WorkflowExecution._process_timeouts--crossover with--dataset/ETHPy150Open RDFLib/rdfextras/rdfextras/sparql/query.py/Query.clusterBackward