From 75ba2e73d8ec2425db70fd95555c05c6b2f33aed Mon Sep 17 00:00:00 2001 From: furyhawk Date: Sun, 31 May 2026 11:26:06 +0800 Subject: [PATCH] Make backend port configurable via .env and update related configurations --- .env.example | 1 + Dockerfile | 2 +- Makefile | 11 +++++++---- README.md | 6 ++++-- app/core/config.py | 1 + docker-compose.yml | 4 ++-- tests/core/test_config.py | 13 +++++++++++++ 7 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 tests/core/test_config.py diff --git a/.env.example b/.env.example index 06175de..525b598 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,7 @@ APP_ENV=development APP_DEBUG=false APP_NAME=LTA DataMall Bus Backend APP_VERSION=0.1.0 +APP_PORT=8000 DATAMALL_BASE_URL=https://datamall2.mytransport.sg/ltaodataservice REQUEST_TIMEOUT_SECONDS=10 MAX_CONNECTIONS=200 diff --git a/Dockerfile b/Dockerfile index 346a880..38ec476 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,4 +19,4 @@ COPY openapi.json ./openapi.json EXPOSE 8000 -CMD ["uv", "run", "gunicorn", "app.main:app", "-k", "uvicorn.workers.UvicornWorker", "-w", "4", "-b", "0.0.0.0:8000", "--access-logfile", "-", "--error-logfile", "-"] +CMD ["sh", "-c", "uv run gunicorn app.main:app -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:${APP_PORT:-8000} --access-logfile - --error-logfile -"] diff --git a/Makefile b/Makefile index 754c14b..6800564 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ APP_MODULE=app.main:app HOST=0.0.0.0 -PORT=8000 + +-include .env + +APP_PORT ?= 8000 PYTHON_RUN=uv run @@ -51,12 +54,12 @@ sync: uv sync run: - $(PYTHON_RUN) uvicorn $(APP_MODULE) --host $(HOST) --port $(PORT) --reload + $(PYTHON_RUN) uvicorn $(APP_MODULE) --host $(HOST) --port $(APP_PORT) --reload dev: run prod: - $(PYTHON_RUN) gunicorn $(APP_MODULE) -k uvicorn.workers.UvicornWorker -w 4 -b $(HOST):$(PORT) --access-logfile - --error-logfile - + $(PYTHON_RUN) gunicorn $(APP_MODULE) -k uvicorn.workers.UvicornWorker -w 4 -b $(HOST):$(APP_PORT) --access-logfile - --error-logfile - compile: $(PYTHON_RUN) python -m compileall app @@ -70,7 +73,7 @@ image-build: check-engine $(CONTAINER_ENGINE) build -t lta-datamall-bus-backend:latest . image-run: check-engine - $(CONTAINER_ENGINE) run -d --name lta-datamall-bus-backend --env-file .env -p 8000:8000 lta-datamall-bus-backend:latest + $(CONTAINER_ENGINE) run -d --name lta-datamall-bus-backend --env-file .env -p $(APP_PORT):$(APP_PORT) lta-datamall-bus-backend:latest image-stop: check-engine -$(CONTAINER_ENGINE) stop lta-datamall-bus-backend diff --git a/README.md b/README.md index f25513d..e3853fc 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ FastAPI backend platform for LTA DataMall Bus Transport APIs, dockerized for pro - Valkey caching layer with graceful fallback when cache is unavailable - Scalable runtime with Gunicorn + Uvicorn workers - API key loaded from `.env` (`DATAMALL_API_KEY`) +- Backend port configurable via `.env` (`APP_PORT`) - Bus Transport endpoints exposed under `/api/v1` - Container health endpoints: `/healthz`, `/readyz` @@ -34,7 +35,7 @@ uv sync 4. Start the app: ```bash -uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload +uv run uvicorn app.main:app --host 0.0.0.0 --port ${APP_PORT:-8000} --reload ``` ## Docker Run @@ -49,7 +50,7 @@ docker compose up --build -d 3. Check health: ```bash -curl http://localhost:8000/healthz +curl http://localhost:${APP_PORT:-8000}/healthz ``` The compose stack includes a Valkey service for caching. @@ -62,6 +63,7 @@ Set in `.env`: - `VALKEY_URL=redis://valkey:6379/0` - `VALKEY_CONNECT_TIMEOUT_SECONDS=1` - `VALKEY_DEFAULT_TTL_SECONDS=120` +- `APP_PORT=8000` Current cache behavior: diff --git a/app/core/config.py b/app/core/config.py index 4868b47..90588fd 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -11,6 +11,7 @@ class Settings(BaseSettings): app_env: str = "development" app_debug: bool = False app_version: str = "0.1.0" + app_port: int = Field(8000, ge=1, le=65535) datamall_base_url: str = "https://datamall2.mytransport.sg/ltaodataservice" datamall_api_key: str = Field(..., description="LTA DataMall AccountKey") diff --git a/docker-compose.yml b/docker-compose.yml index bc0831d..3844768 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,9 +16,9 @@ services: depends_on: - valkey ports: - - "8000:8000" + - "${APP_PORT:-8000}:${APP_PORT:-8000}" healthcheck: - test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthz', timeout=3)"] + test: ["CMD", "python", "-c", "import os, urllib.request; urllib.request.urlopen(f'http://localhost:{os.getenv(\"APP_PORT\", \"8000\")}/healthz', timeout=3)"] interval: 30s timeout: 5s retries: 3 diff --git a/tests/core/test_config.py b/tests/core/test_config.py new file mode 100644 index 0000000..5c5594a --- /dev/null +++ b/tests/core/test_config.py @@ -0,0 +1,13 @@ +from app.core.config import Settings + + +def test_settings_default_backend_port_is_8000(): + settings = Settings(datamall_api_key="test-account-key") + + assert settings.app_port == 8000 + + +def test_settings_reads_backend_port_from_env_value(): + settings = Settings(datamall_api_key="test-account-key", app_port=9010) + + assert settings.app_port == 9010 \ No newline at end of file