title: Cancel nested coroutines in python asyncio
body: <p>In my application, I have a coroutine, which may await on several other coroutines, and each if this coroutines, may await on another ones and so on.
  If one of such coroutines fails, there is no need to execute all others, that was not executed yet. (<em>In my case this is even harmful, and I want to launch several rollback coroutines instead</em>).
  So, how do I cancel execution of all nested coroutines? Here is what I have for now:</p>
  
  <pre><code>import asyncio
  
  async def foo():
      for i in range(5):
          print('Foo', i)
          await asyncio.sleep(0.5)
      print('Foo2 done')
  
  async def bar():
      await asyncio.gather(bar1(), bar2())
  
  
  async def bar1():
      await asyncio.sleep(1)
      raise Exception('Boom!')
  
  
  async def bar2():
      for i in range(5):
          print('Bar2', i)
          await asyncio.sleep(0.5)
      print('Bar2 done')
  
  
  async def baz():
      for i in range(5):
          print('Baz', i)
          await asyncio.sleep(0.5)
  
  async def main():
      task_foo = asyncio.Task(foo())
      task_bar = asyncio.Task(bar())
      try:
          await asyncio.gather(task_foo, task_bar)
      except Exception:
          print('One task failed. Canceling all')
          task_foo.cancel()
          task_bar.cancel()
      print('Now we want baz')
      await baz()
  
  if __name__ == '__main__':
      loop = asyncio.get_event_loop()
      try:
          loop.run_until_complete(main())
      finally:
          loop.close()
  </code></pre>
  
  <p>This obviously does not work. As you can see, <code>foo</code> coroutine is canceled, as I want, but <code>bar2</code> is still running:</p>
  
  <pre><code>Foo 0
  Bar2 0
  Foo 1
  Bar2 1
  Foo 2
  Bar2 2
  One task failed. Canceling all
  Now we want baz
  Baz 0
  Bar2 3
  Baz 1
  Bar2 4
  Baz 2
  Bar2 done
  Baz 3
  Baz 4
  </code></pre>
  
  <p>So, I'm definitely doing something wrong. What is the correct approach here?</p>