#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?