code: 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()
docs: SWF timeouts can happen on different objects (workflow executions,
          activity tasks, decision tasks) and should be processed in order.
  
          A specific timeout can change the workflow execution state and have an
          impact on other timeouts: for instance, if the workflow execution
          timeouts, subsequent timeouts on activity or decision tasks are
          irrelevant ; if an activity task timeouts, other timeouts on this task
          are irrelevant, and a new decision is fired, which could well timeout
          before the end of the workflow.
  
          So the idea here is to find the earliest timeout that would have been
          triggered, process it, then make the workflow state progress and repeat
          the whole process.