reuse the code from quart_common.web.env to import env_bool and env_int into all classes that are useing this functions
This commit is contained in:
+1
-1
Submodule quart_common updated: 823560fdcd...be555d897e
+5
-23
@@ -1,4 +1,5 @@
|
|||||||
from quart_common.web.logger import build_logger, await_log
|
from quart_common.web.logger import build_logger, await_log
|
||||||
|
from quart_common.web.env import env_bool, env_int
|
||||||
from server.Files import read_file
|
from server.Files import read_file
|
||||||
|
|
||||||
from server.game_state_store import GameStateStoreBuilder
|
from server.game_state_store import GameStateStoreBuilder
|
||||||
@@ -64,7 +65,7 @@ class Server:
|
|||||||
self.dashboard_ws_hub = DashboardWebSocketHub()
|
self.dashboard_ws_hub = DashboardWebSocketHub()
|
||||||
dashboard_event_origin = f'worker-{os.getpid()}-{int(time.time() * 1000)}'
|
dashboard_event_origin = f'worker-{os.getpid()}-{int(time.time() * 1000)}'
|
||||||
dashboard_events_channel = os.getenv('DASHBOARD_EVENTS_CHANNEL', 'snake:dashboard:events')
|
dashboard_events_channel = os.getenv('DASHBOARD_EVENTS_CHANNEL', 'snake:dashboard:events')
|
||||||
dashboard_events_enabled = (self.metrics_backend_normalized == 'redis' and self._env_bool('DASHBOARD_EVENTS_ENABLED', True))
|
dashboard_events_enabled = (self.metrics_backend_normalized == 'redis' and env_bool('DASHBOARD_EVENTS_ENABLED', True))
|
||||||
|
|
||||||
self.metrics_collector = MetricsCollector(
|
self.metrics_collector = MetricsCollector(
|
||||||
metrics_manager=MetricsStoreBuilder.build(
|
metrics_manager=MetricsStoreBuilder.build(
|
||||||
@@ -80,8 +81,8 @@ class Server:
|
|||||||
game_last_seen_unix=self.game_last_seen_unix,
|
game_last_seen_unix=self.game_last_seen_unix,
|
||||||
game_move_counts=self.game_move_counts,
|
game_move_counts=self.game_move_counts,
|
||||||
)
|
)
|
||||||
self.clear_worker_metrics_on_startup = self._env_bool('METRICS_CLEAR_WORKERS_ON_STARTUP', True)
|
self.clear_worker_metrics_on_startup = env_bool('METRICS_CLEAR_WORKERS_ON_STARTUP', True)
|
||||||
self.worker_metrics_startup_lock_ttl_sec = self._env_int('METRICS_STARTUP_CLEANUP_LOCK_TTL_SEC', 300)
|
self.worker_metrics_startup_lock_ttl_sec = env_int('METRICS_STARTUP_CLEANUP_LOCK_TTL_SEC', 300)
|
||||||
self.dashboard_running_game_stale_sec = 600
|
self.dashboard_running_game_stale_sec = 600
|
||||||
self._startup_worker_metrics_cleared = False
|
self._startup_worker_metrics_cleared = False
|
||||||
|
|
||||||
@@ -204,26 +205,7 @@ class Server:
|
|||||||
return str(version)
|
return str(version)
|
||||||
|
|
||||||
def _get_stale_game_timeout_sec(self) -> int:
|
def _get_stale_game_timeout_sec(self) -> int:
|
||||||
value = os.getenv('SNAKE_STUCK_GAME_TIMEOUT_SEC', '180')
|
return max(30, env_int('SNAKE_STUCK_GAME_TIMEOUT_SEC', 180))
|
||||||
try:
|
|
||||||
return max(30, int(value))
|
|
||||||
except ValueError:
|
|
||||||
return 180
|
|
||||||
|
|
||||||
def _env_bool(self, name:str, default:bool=False) -> bool:
|
|
||||||
value = os.getenv(name)
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
return value.strip().lower() in {'1', 'true', 'yes', 'on'}
|
|
||||||
|
|
||||||
def _env_int(self, name:str, default:int) -> int:
|
|
||||||
value = os.getenv(name)
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
try:
|
|
||||||
return int(value)
|
|
||||||
except ValueError:
|
|
||||||
return default
|
|
||||||
|
|
||||||
async def _create_game_board(self, game_state:dict) -> GameBoard:
|
async def _create_game_board(self, game_state:dict) -> GameBoard:
|
||||||
game_id = game_state['game']['id']
|
game_id = game_state['game']['id']
|
||||||
|
|||||||
+5
-9
@@ -2,6 +2,7 @@ from typing import TypedDict
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from quart_common.web.env import env_bool, env_int
|
||||||
from server.Server import Server
|
from server.Server import Server
|
||||||
|
|
||||||
class RunConfig(TypedDict):
|
class RunConfig(TypedDict):
|
||||||
@@ -9,18 +10,13 @@ class RunConfig(TypedDict):
|
|||||||
port: int
|
port: int
|
||||||
debug: bool
|
debug: bool
|
||||||
|
|
||||||
def env_bool(name:str, default:bool=False) -> bool:
|
|
||||||
value = os.environ.get(name)
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
return value.lower() in {'1', 'true', 'yes', 'on'}
|
|
||||||
|
|
||||||
def build_server_from_env(default_snake_type:str) -> Server:
|
def build_server_from_env(default_snake_type:str) -> Server:
|
||||||
data_path = str(Path(__file__).resolve().parent.parent)
|
data_path = str(Path(__file__).resolve().parent.parent)
|
||||||
redis_url = os.environ.get('REDIS_URL', 'redis://localhost:6379/0')
|
redis_url = os.environ.get('REDIS_URL', 'redis://localhost:6379/0')
|
||||||
game_state_backend = os.environ.get('GAME_STATE_BACKEND', 'memory')
|
game_state_backend = os.environ.get('GAME_STATE_BACKEND', 'memory')
|
||||||
game_state_redis_url = os.environ.get('GAME_STATE_REDIS_URL', redis_url)
|
game_state_redis_url = os.environ.get('GAME_STATE_REDIS_URL', redis_url)
|
||||||
game_state_ttl_sec = int(os.environ.get('GAME_STATE_TTL_SEC', '900'))
|
game_state_ttl_sec = env_int('GAME_STATE_TTL_SEC', 900)
|
||||||
|
|
||||||
metrics_backend = os.environ.get('METRICS_BACKEND', None)
|
metrics_backend = os.environ.get('METRICS_BACKEND', None)
|
||||||
if metrics_backend is None:
|
if metrics_backend is None:
|
||||||
@@ -31,14 +27,14 @@ def build_server_from_env(default_snake_type:str) -> Server:
|
|||||||
if metrics_ttl_sec_raw is None:
|
if metrics_ttl_sec_raw is None:
|
||||||
metrics_ttl_sec = (game_state_ttl_sec if metrics_backend.strip().lower() == 'redis' else None)
|
metrics_ttl_sec = (game_state_ttl_sec if metrics_backend.strip().lower() == 'redis' else None)
|
||||||
else:
|
else:
|
||||||
metrics_ttl_sec = int(metrics_ttl_sec_raw)
|
metrics_ttl_sec = env_int('METRICS_TTL_SEC', game_state_ttl_sec)
|
||||||
|
|
||||||
gameplay_db_enabled = env_bool('GAMEPLAY_DB_ENABLED', True)
|
gameplay_db_enabled = env_bool('GAMEPLAY_DB_ENABLED', True)
|
||||||
gameplay_db_path = os.environ.get(
|
gameplay_db_path = os.environ.get(
|
||||||
'GAMEPLAY_DB_PATH',
|
'GAMEPLAY_DB_PATH',
|
||||||
os.path.join(data_path, 'data', 'database', 'gameplay.sqlite3'),
|
os.path.join(data_path, 'data', 'database', 'gameplay.sqlite3'),
|
||||||
)
|
)
|
||||||
gameplay_db_busy_timeout_ms = int(os.environ.get('GAMEPLAY_DB_BUSY_TIMEOUT_MS', '5000'))
|
gameplay_db_busy_timeout_ms = env_int('GAMEPLAY_DB_BUSY_TIMEOUT_MS', 5000)
|
||||||
|
|
||||||
server = Server(
|
server = Server(
|
||||||
data_path=data_path,
|
data_path=data_path,
|
||||||
@@ -66,6 +62,6 @@ def build_server_from_env(default_snake_type:str) -> Server:
|
|||||||
def build_run_config() -> RunConfig:
|
def build_run_config() -> RunConfig:
|
||||||
return {
|
return {
|
||||||
'host': os.environ.get('HOST', '0.0.0.0'),
|
'host': os.environ.get('HOST', '0.0.0.0'),
|
||||||
'port': int(os.environ.get('PORT', '8000')),
|
'port': env_int('PORT', 8000),
|
||||||
'debug': env_bool('DEBUG'),
|
'debug': env_bool('DEBUG'),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,34 +2,18 @@ from pathlib import Path
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from quart_common.web.env import env_bool, env_int
|
||||||
from server.dataset.DatasetIO import DatasetIO
|
from server.dataset.DatasetIO import DatasetIO
|
||||||
|
|
||||||
class RLBootstrapDataset:
|
class RLBootstrapDataset:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.enabled = self._env_bool("RL_BOOTSTRAP_ENABLED", default=False)
|
self.enabled = env_bool("RL_BOOTSTRAP_ENABLED", default=False)
|
||||||
self.min_base_rows = self._env_int("RL_MIN_BASE_ROWS", default=5000)
|
self.min_base_rows = env_int("RL_MIN_BASE_ROWS", default=5000)
|
||||||
self.base_dataset_path = Path(os.getenv("RL_BASE_DATASET", "data/dataset/best_moves.jsonl"))
|
self.base_dataset_path = Path(os.getenv("RL_BASE_DATASET", "data/dataset/best_moves.jsonl"))
|
||||||
self.output_path = Path(os.getenv("RL_BOOTSTRAP_OUTPUT", "data/dataset/rl_bootstrap.jsonl"))
|
self.output_path = Path(os.getenv("RL_BOOTSTRAP_OUTPUT", "data/dataset/rl_bootstrap.jsonl"))
|
||||||
self.max_bytes = int(float(os.getenv("RL_BOOTSTRAP_MAX_MB", "50")) * 1024 * 1024)
|
self.max_bytes = int(float(os.getenv("RL_BOOTSTRAP_MAX_MB", "50")) * 1024 * 1024)
|
||||||
self.needs_more_data = False
|
self.needs_more_data = False
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _env_bool(name:str, default:bool=False) -> bool:
|
|
||||||
value = os.getenv(name)
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
return value.lower() in {"1", "true", "yes", "on"}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _env_int(name:str, default:int) -> int:
|
|
||||||
value = os.getenv(name)
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
try:
|
|
||||||
return int(value)
|
|
||||||
except ValueError:
|
|
||||||
return default
|
|
||||||
|
|
||||||
def refresh_state(self):
|
def refresh_state(self):
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
self.needs_more_data = False
|
self.needs_more_data = False
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from typing import Any, cast
|
|||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from quart_common.web.env import env_int
|
||||||
from server.dataset.RLBootstrapDataset import RLBootstrapDataset
|
from server.dataset.RLBootstrapDataset import RLBootstrapDataset
|
||||||
|
|
||||||
from snakes.TemplateSnake import TemplateSnake
|
from snakes.TemplateSnake import TemplateSnake
|
||||||
@@ -43,9 +44,9 @@ class BestBattleSnake(TemplateSnake):
|
|||||||
self.duel_style = self._get_duel_style()
|
self.duel_style = self._get_duel_style()
|
||||||
self.timeout_buffer_ms = self._get_timeout_buffer_ms()
|
self.timeout_buffer_ms = self._get_timeout_buffer_ms()
|
||||||
self.rl_bootstrap = RLBootstrapDataset()
|
self.rl_bootstrap = RLBootstrapDataset()
|
||||||
self.future_planning_depth = max(1, min(4, self._env_int("BATTLE_FUTURE_PLANNING_DEPTH", default=2)))
|
self.future_planning_depth = max(1, min(4, env_int("BATTLE_FUTURE_PLANNING_DEPTH", default=2)))
|
||||||
self.future_planning_branch = max(1, min(3, self._env_int("BATTLE_FUTURE_PLANNING_BRANCH", default=2)))
|
self.future_planning_branch = max(1, min(3, env_int("BATTLE_FUTURE_PLANNING_BRANCH", default=2)))
|
||||||
self.future_planning_min_time_ms = max(25, self._env_int("BATTLE_FUTURE_PLANNING_MIN_MS", default=70))
|
self.future_planning_min_time_ms = max(25, env_int("BATTLE_FUTURE_PLANNING_MIN_MS", default=70))
|
||||||
|
|
||||||
def _get_duel_style(self) -> str:
|
def _get_duel_style(self) -> str:
|
||||||
"""Resolve duel tuning style from `BATTLE_SNAKE_DUEL_STYLE` or `DUEL_STYLE`."""
|
"""Resolve duel tuning style from `BATTLE_SNAKE_DUEL_STYLE` or `DUEL_STYLE`."""
|
||||||
@@ -86,15 +87,6 @@ class BestBattleSnake(TemplateSnake):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return 120
|
return 120
|
||||||
|
|
||||||
def _env_int(self, name:str, default:int) -> int:
|
|
||||||
value = os.getenv(name)
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
try:
|
|
||||||
return int(value)
|
|
||||||
except ValueError:
|
|
||||||
return default
|
|
||||||
|
|
||||||
def choose_move(self, game_data:GameBoard) -> str:
|
def choose_move(self, game_data:GameBoard) -> str:
|
||||||
"""Pick the next move from a Battlesnake move request.
|
"""Pick the next move from a Battlesnake move request.
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ from typing import Any, cast
|
|||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
import heapq, os
|
import heapq, os
|
||||||
|
|
||||||
|
from quart_common.web.env import env_int
|
||||||
|
|
||||||
from snakes.TemplateSnake import TemplateSnake
|
from snakes.TemplateSnake import TemplateSnake
|
||||||
from server.GameBoard import GameBoard
|
from server.GameBoard import GameBoard
|
||||||
from server.dataset.RLBootstrapDataset import RLBootstrapDataset
|
from server.dataset.RLBootstrapDataset import RLBootstrapDataset
|
||||||
@@ -92,9 +94,9 @@ class UltimateBattleSnake(TemplateSnake):
|
|||||||
self._bfs_cache: dict[tuple, int] = {}
|
self._bfs_cache: dict[tuple, int] = {}
|
||||||
self._bfs_cache_turn: int = -1
|
self._bfs_cache_turn: int = -1
|
||||||
# Config
|
# Config
|
||||||
self._planning_depth = max(1, min(4, self._env_int("BATTLE_FUTURE_PLANNING_DEPTH", 2)))
|
self._planning_depth = max(1, min(4, env_int("BATTLE_FUTURE_PLANNING_DEPTH", 2)))
|
||||||
self._planning_branch = max(1, min(3, self._env_int("BATTLE_FUTURE_PLANNING_BRANCH", 2)))
|
self._planning_branch = max(1, min(3, env_int("BATTLE_FUTURE_PLANNING_BRANCH", 2)))
|
||||||
self._planning_min_ms = max(25, self._env_int("BATTLE_FUTURE_PLANNING_MIN_MS", 70))
|
self._planning_min_ms = max(25, env_int("BATTLE_FUTURE_PLANNING_MIN_MS", 70))
|
||||||
# RL bootstrap dataset recorder
|
# RL bootstrap dataset recorder
|
||||||
self.rl_bootstrap = RLBootstrapDataset()
|
self.rl_bootstrap = RLBootstrapDataset()
|
||||||
|
|
||||||
@@ -106,12 +108,6 @@ class UltimateBattleSnake(TemplateSnake):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return 130
|
return 130
|
||||||
|
|
||||||
def _env_int(self, name: str, default: int) -> int:
|
|
||||||
try:
|
|
||||||
return int(os.getenv(name, str(default)))
|
|
||||||
except ValueError:
|
|
||||||
return default
|
|
||||||
|
|
||||||
def _get_duel_style(self) -> str:
|
def _get_duel_style(self) -> str:
|
||||||
raw = os.getenv("BATTLE_SNAKE_DUEL_STYLE", os.getenv("DUEL_STYLE", "balanced"))
|
raw = os.getenv("BATTLE_SNAKE_DUEL_STYLE", os.getenv("DUEL_STYLE", "balanced"))
|
||||||
style = raw.strip().lower()
|
style = raw.strip().lower()
|
||||||
@@ -138,7 +134,7 @@ class UltimateBattleSnake(TemplateSnake):
|
|||||||
self.game_board = game_data
|
self.game_board = game_data
|
||||||
self.calculations = []
|
self.calculations = []
|
||||||
|
|
||||||
timeout_ms = game_data.get_timeout() if hasattr(game_data, "get_timeout") else 500
|
timeout_ms = (game_data.get_timeout() if hasattr(game_data, "get_timeout") else 500)
|
||||||
deadline = perf_counter() + (max(50, timeout_ms - self._get_timeout_buffer_ms()) / 1000.0)
|
deadline = perf_counter() + (max(50, timeout_ms - self._get_timeout_buffer_ms()) / 1000.0)
|
||||||
|
|
||||||
game_id = getattr(game_data, "id", None)
|
game_id = getattr(game_data, "id", None)
|
||||||
|
|||||||
Reference in New Issue
Block a user