Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 73 additions & 73 deletions client/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@
"tw-animate-css": "^1.4.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.57.2",
"vite": "^8.0.2"
"vite": "^8.0.3"
}
}
8 changes: 7 additions & 1 deletion config/infra/docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ services:
- traefik.http.routers.${PROJECT?}-${ENV?}-mailcatcher.entrypoints=web
- traefik.http.services.${PROJECT?}-${ENV?}-mailcatcher.loadbalancer.server.port=1080

migrations:
migrate-database:
pull_policy: build
build:
context: ../../server
target: dev

reindex-meilisearch:
pull_policy: build
build:
context: ../../server
Expand Down
78 changes: 75 additions & 3 deletions config/infra/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ services:
- traefik-public
- default

depends_on:
database:
condition: service_healthy
restart: true

environment:
- ADMINER_DESIGN=dracula
- ADMINER_DEFAULT_SERVER=database
Expand Down Expand Up @@ -66,9 +71,9 @@ services:
- traefik.http.routers.${PROJECT?}-${ENV?}-meilisearch.rule=Host(`search-${DOMAIN?}`)
- traefik.http.routers.${PROJECT?}-${ENV?}-meilisearch.entrypoints=websecure

migrations:
migrate-database:
image: ${DOCKER_REGISTRY?}/${PROJECT?}-${ENV?}-server:${TAG?}
container_name: ${PROJECT?}-${ENV?}-migrations
container_name: ${PROJECT?}-${ENV?}-migrate-database
restart: no
extra_hosts:
- host.docker.internal:host-gateway
Expand Down Expand Up @@ -123,6 +128,68 @@ services:

command: alembic upgrade head

reindex-meilisearch:
image: ${DOCKER_REGISTRY?}/${PROJECT?}-${ENV?}-server:${TAG?}
container_name: ${PROJECT?}-${ENV?}-reindex-meilisearch
restart: no
extra_hosts:
- host.docker.internal:host-gateway

depends_on:
database:
condition: service_healthy
restart: true
meilisearch:
condition: service_healthy
restart: true
migrate-database:
condition: service_completed_successfully

environment:
- ENV=${ENV?}
- LOG_LEVEL=${LOG_LEVEL?}
- CLIENT_URL=${CLIENT_URL?}

- ADMIN__USERNAME=${ADMIN__USERNAME?}
- ADMIN__EMAIL=${ADMIN__EMAIL?}
- ADMIN__FIRST_NAME=${ADMIN__FIRST_NAME?}
- ADMIN__LAST_NAME=${ADMIN__LAST_NAME?}
- ADMIN__PASSWORD=${ADMIN__PASSWORD?}

- JWT__SECRET_KEY=${JWT__SECRET_KEY?}
- JWT__ALGORITHM=${JWT__ALGORITHM?}
- JWT__ACCESS_TOKEN_EXPIRE_MINUTES=${JWT__ACCESS_TOKEN_EXPIRE_MINUTES?}
- JWT__REFRESH_TOKEN_EXPIRE_DAYS=${JWT__REFRESH_TOKEN_EXPIRE_DAYS?}

# internal host & port
- DB__HOST=database
- DB__PORT=5432
- DB__NAME=${DB__NAME?}
- DB__USER=${DB__USER?}
- DB__PASSWORD=${DB__PASSWORD?}

# internal host & port
- MS__HOST=meilisearch
- MS__PORT=7700
- MS__MASTER_KEY=${MS__MASTER_KEY?}

- EMAIL__BACKEND=${EMAIL__BACKEND?}
- EMAIL__EMAIL_FROM=${EMAIL__EMAIL_FROM?}
# internal host
- EMAIL__SMTP_HOST=host.docker.internal
- EMAIL__SMTP_PORT=${EMAIL__SMTP_PORT?}
# not required for non-smtp backends
- EMAIL__SMTP_USERNAME=${EMAIL__SMTP_USERNAME}
- EMAIL__SMTP_PASSWORD=${EMAIL__SMTP_PASSWORD}

- GH__BACKEND=${GH__BACKEND?}
# not required for console backend
- GH__REPO_OWNER=${GH__REPO_OWNER}
- GH__TOKEN=${GH__TOKEN}
- GH__ISSUE_ASSIGNEE=${GH__ISSUE_ASSIGNEE}

command: python3 -m app.scripts.reindex_meilisearch

server:
image: ${DOCKER_REGISTRY?}/${PROJECT?}-${ENV?}-server:${TAG?}
container_name: ${PROJECT?}-${ENV?}-server
Expand All @@ -137,7 +204,12 @@ services:
database:
condition: service_healthy
restart: true
migrations:
meilisearch:
condition: service_healthy
restart: true
migrate-database:
condition: service_completed_successfully
reindex-meilisearch:
condition: service_completed_successfully

volumes:
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"devDependencies": {
"husky": "^9.1.7",
"lint-staged": "^16.4.0",
"npm-check-updates": "^19.6.5",
"npm-check-updates": "^19.6.6",
"prettier": "^3.8.1",
"prettier-plugin-organize-imports": "^4.3.0",
"prettier-plugin-tailwindcss": "^0.7.2",
Expand Down
Empty file added server/app/scripts/__init__.py
Empty file.
43 changes: 43 additions & 0 deletions server/app/scripts/reindex_meilisearch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import asyncio
import logging

from app.core.config import get_settings
from app.core.dependencies import build_ms_client, get_db_sessionmaker
from app.core.logging import setup_logging
from app.services.search import reindex

logger = logging.getLogger(__name__)


async def _run() -> None:
settings = get_settings()
settings.log_dir.mkdir(parents=True, exist_ok=True)
setup_logging(settings.log_dir, settings.env, settings.log_level)

sessionmaker = get_db_sessionmaker(
settings.db.url,
settings.is_prod_like,
)
ms_client = build_ms_client(
settings.ms.host,
settings.ms.port,
settings.ms.master_key,
)

logger.info("Starting full Meilisearch reindex")

async with sessionmaker() as db_session:
await reindex(
db_session=db_session,
ms_client=ms_client,
)

logger.info("Finished full Meilisearch reindex")


def main() -> None:
asyncio.run(_run())


if __name__ == "__main__":
main()
9 changes: 5 additions & 4 deletions server/app/services/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ async def reindex(
db_session: AsyncSession,
ms_client: AsyncClient,
):
indexes = await ms_client.get_indexes() or []
for idx in indexes:
logger.info(f"Deleting index: {idx.uid}")
await ms_client.delete_index_if_exists(idx.uid)

task = await _index_muscle_groups(db_session, ms_client)
logger.info(f"Reindexing muscle groups with task id: {task}")

Expand All @@ -47,8 +52,6 @@ async def _index_muscle_groups(
muscle_groups = result.scalars().all()
docs = [to_muscle_group_public(mg) for mg in muscle_groups]

await ms_client.delete_index_if_exists(SearchIndex.MUSCLE_GROUPS)

settings = MeilisearchSettings(
searchable_attributes=[
"name",
Expand All @@ -70,8 +73,6 @@ async def _index_exercises(
exercises = await query_exercises(db_session, base=False)
docs = [to_exercise_document(e) for e in exercises]

await ms_client.delete_index_if_exists(SearchIndex.EXERCISES)

settings = MeilisearchSettings(
searchable_attributes=[
"name",
Expand Down
14 changes: 14 additions & 0 deletions server/app/tests/services/search/test_reindex.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from types import SimpleNamespace

from meilisearch_python_sdk import AsyncClient
from pytest import MonkeyPatch
from sqlalchemy.ext.asyncio import AsyncSession
Expand All @@ -11,16 +13,28 @@ async def test_reindex(
monkeypatch: MonkeyPatch,
):
calls: list[str] = []
deleted_indexes: list[str] = []

async def fake_get_indexes() -> list[SimpleNamespace]:
return [SimpleNamespace(uid="muscle_groups")]

async def fake_delete_index_if_exists(uid: str) -> None:
deleted_indexes.append(uid)

async def fake_muscle_groups(db_session: AsyncSession, client: AsyncClient) -> None:
calls.append("muscle")

async def fake_exercises(db_session: AsyncSession, client: AsyncClient) -> None:
calls.append("exercise")

monkeypatch.setattr(ms_client, "get_indexes", fake_get_indexes)
monkeypatch.setattr(
ms_client, "delete_index_if_exists", fake_delete_index_if_exists
)
monkeypatch.setattr("app.services.search._index_muscle_groups", fake_muscle_groups)
monkeypatch.setattr("app.services.search._index_exercises", fake_exercises)

await reindex(db_session, ms_client)

assert deleted_indexes == ["muscle_groups"]
assert calls == ["muscle", "exercise"]
2 changes: 1 addition & 1 deletion server/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ log_cli_level = "INFO"
[tool.coverage.run]
branch = true
source = ["app"]
omit = ["app/migrations/*", "app/tests/*", "conftest.py"]
omit = ["app/migrations/*", "app/scripts/*", "app/tests/*", "conftest.py"]

[tool.coverage.report]
show_missing = true
Expand Down
Loading
Loading