Django Timer issue

I'm writing a Chess App with Django and Django Channels. The problem I have ran into is this: During the game, each time a player makes a move, the opponent's timer starts to count down. I've managed to achieve this using tasks. The issue is that each time the loop decrements the timer and broadcasts both timers to the clients, it calls the database and saves the current timer value to the model. That happens every second, and I've come to realize that it is a bad practice (saving to the database every second), and it's been causing me some bugs. My question is, what is the correct approach here? I want to keep track of the timers on the backend's side, so for example when it hits zero, I can stop the game, or when a player disconnects, the timer will keep on counting down.

async def timer_handler(self, event):
        moving_color = event['text']
        username = self.scope['user'].username
        consumer_color = self.game_obj.get_color(username)
        if consumer_color == moving_color:
            if self.timer_task != None:
                asyncio.Task.cancel(self.timer_task)
                self.timer_task = None
        elif consumer_color == self.opposite_color(moving_color):
            if self.timer_task == None:
                self.timer_task = asyncio.create_task(self.timer_countdown(self.opposite_color(moving_color)))
            else:
                try:
                    raise Exception("Scheduled a timer task for a timer that's already running")
                finally:
                    print('self.timer_task:', self.timer_task)

    
    async def timer_countdown(self, color):
        timer = self.get_timer(color)
        while True:
            await asyncio.sleep(1)
            timer -= 1
            await database_sync_to_async(self.update_timer)(timer, color)
            timer_formatted = self.to_timer_format(timer)
            data = {
                'type': 'time',
                'time': timer_formatted,
                'timer_color': color
            }
            await self.channel_layer.group_send(
                self.game_room_name,
                {
                    'type': 'basic_broadcast',
                    'text': data
                }
            )

    def update_timer(self, time, timer_color):
        game_obj = Game.objects.get(id=self.game_id)
        if timer_color == 'white':
            game_obj.timer_white = time
        elif timer_color == 'black':
            game_obj.timer_black = time
        else:
            try:
                raise Exception('Undefined timer color')
            finally:
                print('timer_color:', timer_color)
        game_obj.save()

The timer_handler function is called every time a player makes a move. link to the whole project: https://github.com/mephis71/django_chess

Back to Top