Запустите игровой цикл на сервере flask

#flask #celery #flask-socketio #game-loop #celerybeat

#колба #сельдерей #колба-носок #игровой цикл #стук сельдерея

Вопрос:

Я создаю сайт азартных игр, используя python flask.

Сайт состоит из нескольких онлайн-игр, в которые играют одновременно все игроки. Это требует, чтобы игровой цикл где-то запускался, сохранял текущее состояние игры и обновлял его по ходу игры.

Пример: Игра в рулетку — рулетка вращается каждые 15 секунд, цикл реализует обратный отсчет и показывает результат каждые 15 секунд, состояние передается клиентам каждую секунду, которые выдают соответствующий ответ интерфейса.

До сих пор моим решением было выполнение задачи с сельдереем:

 @celery.task def coin_toss_game_loop():  process_lock = lock_manager.lock("coin_toss_game_loop", 1000 * 60)  if process_lock:    game_name = "coinv1"   coin_game = Game.objects(game_name=game_name)[0]  current_nonce = coin_game.nonce   1   coin_game_seed = GameSeed.objects(game_id=coin_game.id, nonce=current_nonce)[0]  server_seed = coin_game_seed.seed_crypto  client_seed = coin_game_seed.seed_client  result = coin_game_seed.result   round_seed_hash = hashlib.sha256(server_seed.encode('utf-8')).hexdigest()   #fetch 10 previous rounds  previous_rounds = []  query_set = GameSeed.objects(game_id=coin_game.id, nonce__lt=current_nonce, nonce__gte=current_nonce - 10)  for game_seed_pre in query_set:  data_dict = {  "nonce": game_seed_pre.nonce,  "round_seed" : game_seed_pre.seed_crypto,  "client_seed" : game_seed_pre.seed_client,  "round_seed_hash": hashlib.sha256(game_seed_pre.seed_crypto.encode('utf-8')).hexdigest(),  "round_result": str(game_seed_pre.result),  }  previous_rounds.append(data_dict)   initial_emit_data = {  "moment": "startup",  "meta": {  "gameId": str(coin_game_seed.pk),  "nonce": current_nonce,  "secs_to_go": 10,  "round_seed_hash": round_seed_hash,  "round_seed" : "",  "client_seed" : client_seed,  "round_result": "",  "previous_rounds" : previous_rounds,  "lock": False  }  }   socketio_celery.emit('gamePing', initial_emit_data, namespace='/coin')   #set time to wait between rounds  for i in range(10, 0, -1):   wait_emit_data = {  "moment": "wait",  "meta": {  "gameId": str(coin_game_seed.pk),  "nonce": current_nonce,  "secs_to_go": i,  "round_seed_hash": round_seed_hash,  "round_seed" : "",  "client_seed" : client_seed,  "round_result": "",  "previous_rounds" : previous_rounds,  "lock" : True if i gt; 2 else False  }  }  socketio_celery.emit('gamePing', wait_emit_data, namespace='/coin')  time.sleep(1)   #lock new bets  coin_game_seed.lock = True  coin_game_seed.save()   #send final result  final_emit_data = {  "moment": "final",  "meta": {  "gameId": str(coin_game_seed.pk),  "nonce": current_nonce,  "secs_to_go": 0,  "round_seed_hash": round_seed_hash,  "round_seed" : server_seed,  "client_seed" : client_seed,  "round_result": str(result),  "previous_rounds" : previous_rounds,  "lock" : True  }  }  socketio_celery.emit('gamePing', final_emit_data, namespace='/coin')   coin_game.nonce = current_nonce  coin_game.save()   lock_manager.unlock(process_lock)   #process bets and deliver wins  game_id = str(coin_game_seed.pk)  namespace = "/coin"  tickets_to_process = GameTicket.objects(game_id=game_id, is_processed__ne=True)  for ticket in tickets_to_process:  if str(ticket.user_choice) == result:  ticket(  is_processed=True,  win_loss=True,  prize_won = ticket.bet_value * ticket.prize_multiplier,  )  ticket.save()  else:  ticket(  is_processed=True,  win_loss=False,  prize_won = 0,  )  ticket.save()  socketio_celery.emit('gamePing2', {"status": "updateBalance"}, namespace=namespace)  

Эта задача не является циклом, но я использую ритм сельдерея, чтобы планировать выполнение задачи каждые 15 секунд:

 celery.conf.beat_schedule = {  "coin_toss_game": {  "task": "app.tasks.coin_toss_game_loop",  "schedule": 15  },  }  

Проблема в том, что сельдерей зависает после выполнения 2 задач. После долгого чтения и чтения документации я начинаю думать, что сельдерей был плохим выбором для этой задачи. Каков был бы рекомендуемый способ реализации такого игрового цикла в flask?