title: How to run an async function without blocking the execution in Django channels
body: <p>I have an <code>AsyncWebsocketConsumer</code> running django channels for an online turn-based game.</p>
  <p>There is need to verify that the player associated to the current turn is online, and if they aren't, the sever should wait 5 seconds to give the player a chance to come back before updating the turn and passing onto the next player.</p>
  <p>At the end of the function that sends the new state to connected players, which is called every time the client sends the socket a message modifying the state, you have these two lines:</p>
  <pre><code>await self.send_new_state_to_all_players(event_specifics)
  await self.check_current_player_online(game_id) # routine to handle the case where current player isn't online  
  </code></pre>
  <p>The method <code>check_current_player_online()</code> does this:</p>
  <pre><code>async def check_current_player_online(self, game_id):
          current_turn_player_number = await self.get_current_turn(game_id)
          if await self.is_online(await self.get_player_id_from_number(game_id, current_turn_player_number)): # if current player is online, resume normal game flow
              return
  
          await asyncio.sleep(5)
  
          if not await self.is_online(await self.get_player_id_from_number(game_id, current_turn_player_number)): # if player hasn't come back, increment turn
              await self.increment_turn(game_id)
              await self.send_new_state_to_all_players({
                  'type': 'pass_turn',
              })
  </code></pre>
  <p>Expected behavior: when the turn of a player who isn't online comes, every player should receive the new state sent by <code>send_new_state_to_all_players</code>, and be informed it's <em>xyz</em>'s turn (the offline player), then after 5 seconds, if <em>xyz</em> hasn't come back online, the socket should send a new <code>state</code> message after updating the turn.</p>
  <p>Actual behavior: the intended behavior takes place for everyone <em>but</em> the last player who sent a message to the socket, which is the one who triggered the <code>check_current_player_online()</code>. They won't receive the first new state, and will only receive the updated state and the second updated state from <code>check_current_player_online()</code>, together, after 5 seconds, when the function has finished running.</p>
  <p>Here's the implementation of <code>send_new_state_to_all_players</code> along with the handler it calls:</p>
  <pre><code>async def send_new_state_to_all_players(self, event_specifics):
          game_id = self.scope['url_route']['kwargs']['game_id']
          for player in await sync_to_async(list)(Player.objects.filter(Q(game_id=game_id))):
              await self.channel_layer.group_send(
                  self.game_group_name,
                  {
                      'type': 'game_state_handler',
                      'player_id': player.pk,
                      'event_specifics': event_specifics,
                  }
              )
  
  # handler
      async def game_state_handler(self, event):
          if(self.scope['session']['player_id'] != event['player_id']):
              return
          state = await self.get_game_state(self.scope['url_route']['kwargs']['game_id'], event['player_id'])
          await self.send(text_data=json.dumps({
              'type': 'new_state',
              'state': state,
              'event_specifics': event['event_specifics'],
          }))
  
  # function called by the handler
  
  @database_sync_to_async
      def get_game_state(self, game_id, player_id):
          # Returns a dictionary holding the game's state
          game = Game.objects.get(pk=game_id)
          
          this_player = Player.objects.get(pk=player_id)
          this_player_cards = CardsInHand.objects.filter(player_id=player_id)
          my_cards = []
          for card in this_player_cards:
              card_str = str(card.card_number) + card.card_seed
              my_cards.append(card_str)
          
          other_players_list = []
          other_players = Player.objects.filter(Q(game_id=game_id) &amp; ~Q(pk=player_id))
          for player in other_players:
              player_data = {
                  'number': player.player_number,
                  'is_online': player.is_online,
                  'number_of_cards': CardsInHand.objects.filter(player_id=player).count(),
                  'name': player.name,
              }
              other_players_list.append(player_data)
          state = {
              'current_turn': game.player_current_turn,
              'last_turn': game.player_last_turn,
              'current_card': game.current_card,
              'last_card': game.last_card,
              'number_of_stacked_cards': len(json.loads(game.stacked_cards)),
              'last_amount_played': game.last_amount_played,
              'won_by': game.winning_player if game.has_been_won else -1,
              'my_cards': my_cards,
              'other_players_data': other_players_list,
              'my_player_number': this_player.player_number,
          }
  
          return state
  
  
  </code></pre>
  <p>Why does this happen? How do I make this process non-blocking or enforce that the first function be ran till the end before moving onto the second one?</p>