Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
ai company
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
ai company
Commits
b777c5b5
Commit
b777c5b5
authored
Mar 17, 2026
by
Vũ Hoàng Anh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: multi-stage Docker builds, .dockerignore, singleton StarRocks connection
parent
1f2700e1
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
122 additions
and
28 deletions
+122
-28
.dockerignore
backend/.dockerignore
+43
-5
Dockerfile.dev
backend/Dockerfile.dev
+31
-13
Dockerfile.prod
backend/Dockerfile.prod
+43
-5
product_route.py
backend/api/product_route.py
+5
-5
No files found.
backend/.dockerignore
View file @
b777c5b5
# ═══ Git & IDE ═══
.git
.gitignore
.vscode
.idea
*.swp
*.swo
# ═══ Python cache ═══
__pycache__
__pycache__
*.pyc
*.pyc
.env
*.pyo
*.egg-info
.pytest_cache
.mypy_cache
.ruff_cache
# ═══ Virtual environments ═══
.venv
.venv
venv
venv
.git
env
.gitignore
# ═══ Docker ═══
Dockerfile*
docker-compose*
.dockerignore
.dockerignore
logs
data
# ═══ Dev & test files ═══
tests/
*.test.py
setup_readonly_user.py
# ═══ Docs & artifacts ═══
*.md
LICENSE
# ═══ OS files ═══
.DS_Store
Thumbs.db
# ═══ Logs ═══
*.log
logs/
# ═══ Local env backup ═══
.env.local
.env.backup
.env.example
backend/Dockerfile.dev
View file @
b777c5b5
# ============================================================
# ============================================================
# DOCKERFILE.DEV
- Local Development (Hot Reload + Cache
)
# DOCKERFILE.DEV
— Multi-stage Dev Build (Hot Reload
)
# ============================================================
# ============================================================
# Sử dụng Python 3.11 Slim để tối ưu dung lượng
# Stage 1: Builder — install dependencies
# Stage 2: Runtime — dev server with reload
# ============================================================
# ──── Stage 1: Builder ────
FROM python:3.11-slim AS builder
WORKDIR /build
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libpq-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt \
&& pip install --no-cache-dir --user watchdog[watchmedo]
# ──── Stage 2: Runtime ────
FROM python:3.11-slim
FROM python:3.11-slim
# Thiết lập thư mục làm việc
WORKDIR /app
WORKDIR /app
# Thiết lập biến môi trường
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 curl \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get purge -y --auto-remove
ENV PYTHONUNBUFFERED=1
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV ENV=development
ENV ENV=development
# Copy requirements.txt trước để tận dụng Docker cache
# Copy installed packages from builder
COPY requirements.txt .
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
# Cài đặt thư viện Python (Docker layer cache)
RUN pip install -r requirements.txt && pip install watchdog[watchmedo]
#
Copy toàn bộ source code vào image
#
Source code mounted via volume in docker-compose (not COPY)
COPY . .
COPY . .
# Expose port 5000
EXPOSE 5000
EXPOSE 5000
# Health check (optional)
HEALTHCHECK --interval=10s --timeout=5s --start-period=5s --retries=2 \
HEALTHCHECK --interval=10s --timeout=5s --start-period=5s --retries=2 \
CMD
python -c "import requests; requests.get('http://localhost:5000/docs')"
|| exit 1
CMD
curl -f http://localhost:5000/docs
|| exit 1
CMD ["gunicorn", "--workers", "1", "--worker-class", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:5000", "--timeout", "120", "--reload", "server:app"]
CMD ["gunicorn", "--workers", "1", "--worker-class", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:5000", "--timeout", "120", "--reload", "server:app"]
backend/Dockerfile.prod
View file @
b777c5b5
# ============================================================
# DOCKERFILE.PROD — Multi-stage Production Build
# ============================================================
# Stage 1: Build — install dependencies in isolated layer
# Stage 2: Runtime — minimal image with only what's needed
# ============================================================
FROM python:3.11-slim
# ──── Stage 1: Builder ────
FROM python:3.11-slim AS builder
WORKDIR /build
# Install only build-time system deps (if any wheels need compiling)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libpq-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
# Install to user site-packages (no root pollution)
RUN pip install --no-cache-dir --user -r requirements.txt
# ──── Stage 2: Runtime ────
FROM python:3.11-slim
WORKDIR /app
WORKDIR /app
# Minimal runtime deps only
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 curl \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get purge -y --auto-remove
ENV PYTHONUNBUFFERED=1
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV ENV=
development
ENV ENV=
production
COPY requirements.txt .
# Copy only installed packages from builder (no pip cache, no gcc)
RUN pip install -r requirements.txt
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
# Copy application source
COPY . .
COPY . .
EXPOSE 5000
EXPOSE 5000
...
@@ -19,4 +48,13 @@ EXPOSE 5000
...
@@ -19,4 +48,13 @@ EXPOSE 5000
ENV WORKERS=1
ENV WORKERS=1
ENV TIMEOUT=60
ENV TIMEOUT=60
CMD gunicorn server:app --workers $WORKERS --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:5000 --timeout $TIMEOUT
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost:5000/docs || exit 1
CMD gunicorn server:app \
--workers $WORKERS \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:5000 \
--timeout $TIMEOUT \
--access-logfile - \
--error-logfile -
backend/api/product_route.py
View file @
b777c5b5
...
@@ -9,7 +9,7 @@ from typing import Optional
...
@@ -9,7 +9,7 @@ from typing import Optional
from
fastapi
import
APIRouter
,
Query
from
fastapi
import
APIRouter
,
Query
from
fastapi.responses
import
JSONResponse
from
fastapi.responses
import
JSONResponse
from
common.starrocks_connection
import
StarRocksC
onnection
from
common.starrocks_connection
import
get_db_c
onnection
from
agent.tools.product_mapping
import
resolve_color
,
resolve_product_name
,
SYNONYM_TO_DB
from
agent.tools.product_mapping
import
resolve_color
,
resolve_product_name
,
SYNONYM_TO_DB
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -21,7 +21,7 @@ TABLE_NAME = "shared_source.magento_product_dimension_with_text_embedding"
...
@@ -21,7 +21,7 @@ TABLE_NAME = "shared_source.magento_product_dimension_with_text_embedding"
@
router
.
get
(
"/api/products/overview"
,
summary
=
"Product catalog KPI overview"
)
@
router
.
get
(
"/api/products/overview"
,
summary
=
"Product catalog KPI overview"
)
async
def
products_overview
():
async
def
products_overview
():
"""Return aggregate KPIs for the product catalog."""
"""Return aggregate KPIs for the product catalog."""
db
=
StarRocksC
onnection
()
db
=
get_db_c
onnection
()
try
:
try
:
rows
=
await
db
.
execute_query_async
(
f
"""
rows
=
await
db
.
execute_query_async
(
f
"""
SELECT
SELECT
...
@@ -104,7 +104,7 @@ async def products_list(
...
@@ -104,7 +104,7 @@ async def products_list(
offset
:
int
=
Query
(
0
,
ge
=
0
),
offset
:
int
=
Query
(
0
,
ge
=
0
),
):
):
"""Return paginated product listing grouped by internal_ref_code."""
"""Return paginated product listing grouped by internal_ref_code."""
db
=
StarRocksC
onnection
()
db
=
get_db_c
onnection
()
# Build WHERE clauses
# Build WHERE clauses
clauses
=
[]
clauses
=
[]
...
@@ -234,7 +234,7 @@ async def products_colors(
...
@@ -234,7 +234,7 @@ async def products_colors(
code
:
str
=
Query
(
...
,
description
=
"internal_ref_code"
),
code
:
str
=
Query
(
...
,
description
=
"internal_ref_code"
),
):
):
"""Return all color variants for a given internal_ref_code."""
"""Return all color variants for a given internal_ref_code."""
db
=
StarRocksC
onnection
()
db
=
get_db_c
onnection
()
try
:
try
:
variants
=
await
db
.
execute_query_async
(
variants
=
await
db
.
execute_query_async
(
f
"""
f
"""
...
@@ -266,7 +266,7 @@ async def products_colors(
...
@@ -266,7 +266,7 @@ async def products_colors(
@
router
.
get
(
"/api/products/filters"
,
summary
=
"Available filter options"
)
@
router
.
get
(
"/api/products/filters"
,
summary
=
"Available filter options"
)
async
def
products_filters
():
async
def
products_filters
():
"""Return all available filter values for color, product_line, age, season."""
"""Return all available filter values for color, product_line, age, season."""
db
=
StarRocksC
onnection
()
db
=
get_db_c
onnection
()
try
:
try
:
colors
=
await
db
.
execute_query_async
(
f
"""
colors
=
await
db
.
execute_query_async
(
f
"""
SELECT master_color, COUNT(DISTINCT internal_ref_code) AS cnt
SELECT master_color, COUNT(DISTINCT internal_ref_code) AS cnt
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment