Skip to content

Commit 586e54d

Browse files
committed
chore: fix indexing in prod when using multiple worker
1 parent 36d48ff commit 586e54d

File tree

9 files changed

+36
-20
lines changed

9 files changed

+36
-20
lines changed

.github/deploy.sh

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99
# ssh expasychat
1010
## Just restart:
1111
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; XDG_RUNTIME_DIR=/run/user/1001 podman-compose -f compose.prod.yml up --force-recreate -d'
12+
1213
## Pull and restart:
1314
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; git pull ; XDG_RUNTIME_DIR=/run/user/1001 podman-compose -f compose.prod.yml up --force-recreate -d'
14-
## Show logs:
15-
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; XDG_RUNTIME_DIR=/run/user/1001 podman-compose -f compose.prod.yml logs'
1615

17-
## Delete the vector database to re-index from scratch:
18-
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; rm -rf data/qdrant/ data/endpoints_metadata.json'
19-
# Careful as you will need to first run it without compose.prod.yml to regenerate the index, the multiple workers in prod will conflict when re-indexing from scratch
16+
## Pull, build and restart:
17+
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; git pull ; XDG_RUNTIME_DIR=/run/user/1001 podman-compose -f compose.prod.yml up --force-recreate --build -d'
2018

19+
## Re-index the endpoints in running deployment:
20+
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; XDG_RUNTIME_DIR=/run/user/1001 podman-compose -f compose.prod.yml exec api uv run src/sparql_llm/agent/indexing/index_resources.py'
2121

22-
## Re-index without restarting
23-
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; XDG_RUNTIME_DIR=/run/user/1001 podman-compose exec api uv run src/expasy_agent/indexing/index_resources.py'
22+
## Show logs:
23+
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; XDG_RUNTIME_DIR=/run/user/1001 podman-compose -f compose.prod.yml logs'
2424

25-
# Check env variables
25+
## Check env variables
2626
# sudo -u podman bash -c 'cd /var/containers/podman/sparql-llm ; vim .env'
2727

2828
# NOTE: if OOM error, check `dmesg` on server and search for `oom`

.github/workflows/test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ jobs:
1717
matrix:
1818
# os: ["ubuntu-latest", "windows-latest", "macos-latest"]
1919
os: ["ubuntu-latest"]
20-
python-version: ["3.11", "3.12", "3.13", "3.14"]
20+
python-version: ["3.11", "3.12", "3.13"]
21+
# onnxruntime not available for "3.14"
2122

2223
steps:
2324
- uses: actions/checkout@v6

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ Requirements: Docker, nodejs (to build the frontend), and optionally [`uv`](http
263263
CHAT_API_KEY=NOT_SO_SECRET_API_KEY_USED_BY_FRONTEND_TO_AVOID_SPAM_FROM_CRAWLERS
264264
LOGS_API_KEY=SECRET_PASSWORD_TO_EASILY_ACCESS_LOGS_THROUGH_THE_API
265265

266-
OPENAI_API_KEY=sk-proj-YYY
267266
OPENROUTER_API_KEY=sk-YYY
267+
OPENAI_API_KEY=sk-proj-YYY
268268

269269
LANGFUSE_HOST=https://cloud.langfuse.com
270270
LANGFUSE_PUBLIC_KEY=
@@ -292,13 +292,19 @@ Requirements: Docker, nodejs (to build the frontend), and optionally [`uv`](http
292292
* OpenAPI Swagger UI available at http://localhost:8000/docs
293293
* Vector database dashboard UI available at http://localhost:6333/dashboard
294294

295-
In production, you will need to make some changes to the `compose.prod.yml` file to adapt it to your server/proxy setup:
295+
**In production**, you will need to make some changes to the `compose.prod.yml` file to adapt it to your server/proxy setup:
296296

297297
```bash
298298
docker compose -f compose.prod.yml up
299299
```
300300

301-
> All data from the containers are stored persistently in the `data` folder (e.g. vectordb indexes)
301+
Then run the indexing script manually from within the container to index the SPARQL endpoints (need to do it once):
302+
303+
```sh
304+
docker compose -f compose.prod.yml exec api uv run src/sparql_llm/agent/indexing/index_resources.py
305+
```
306+
307+
> All data from the containers are stored persistently in the `data` folder (e.g. vectordb indexes and endpoints metadata)
302308
303309
> [!NOTE]
304310
>

compose.prod.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ services:
1717
- 1.1.1.1
1818
ports:
1919
- 80:80
20+
environment:
21+
- AUTO_INIT=false
2022
# environment:
2123
# - VECTORDB_URL=http://vectordb:6334/
2224
# NOTE: dirty hack to fix a bug with podman internal network on prod server

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ dependencies = [
3434
"SPARQLWrapper >=2.0.0",
3535
"beautifulsoup4 >=4.13.0",
3636
"curies >=0.11.0",
37-
"langchain-core >=1.2.6",
38-
"mcp >=1.25.0",
37+
"mcp >=1.25.0,<2",
3938
"qdrant-client >=1.16.2",
4039
"fastembed >=0.7.4",
41-
"langgraph >=1.0.5",
40+
"langchain-core >=1.2.6",
4241
"langchain-qdrant >=1.1.0",
4342
"langchain-community >=0.4.1",
43+
"langgraph >=1.0.5",
4444
"markdownify >=1.1.0",
4545
"pandas >=2.2.3",
4646
]

src/sparql_llm/agent/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ class Settings(BaseSettings):
127127
embedding_model: str = "BAAI/bge-small-en-v1.5"
128128
embedding_dimensions: int = 384
129129
force_index: bool = False
130+
# Automatically initialize the vector store client, should be False when deploying in prod with multiple workers
131+
auto_init: bool = True
130132

131133
# Sparse embeddings are only used for the entities resolution
132134
sparse_embedding_model: str = "Qdrant/bm25"

src/sparql_llm/agent/indexing/index_resources.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,6 @@ def load_resources(file: str = "expasy_resources_metadata.csv") -> list[Document
157157
def init_vectordb() -> None:
158158
"""Initialize the vectordb with example queries and ontology descriptions from the SPARQL endpoints"""
159159
docs: list[Document] = []
160-
161-
# endpoints_urls = [endpoint["endpoint_url"] for endpoint in settings.endpoints]
162160
prefix_map, _void_schema = get_prefixes_and_schema_for_endpoints(settings.endpoints)
163161

164162
# Gets documents from the SPARQL endpoints

src/sparql_llm/mcp_server.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,21 @@
3131
)
3232

3333
# Check if the docs collection exists and has data, initialize if not
34+
# In prod with multiple workers, auto_init should be set to False to avoid race conditions
3435
try:
35-
collection_exists = qdrant_client.collection_exists(settings.docs_collection_name)
36-
if (
36+
collection_needs_init = (
3737
settings.force_index
3838
or not qdrant_client.collection_exists(settings.docs_collection_name)
3939
or not qdrant_client.get_collection(settings.docs_collection_name).points_count
40-
):
40+
)
41+
if settings.auto_init and collection_needs_init:
4142
logger.info("📊 Initializing vectordb...")
4243
init_vectordb()
44+
elif not settings.auto_init and collection_needs_init:
45+
logger.warning(
46+
f"⚠️ Collection '{settings.docs_collection_name}' does not exist or is empty. Run the following command to initialize it:\n"
47+
"docker compose -f compose.prod.yml exec api uv run src/sparql_llm/agent/indexing/index_resources.py"
48+
)
4349
else:
4450
logger.info(
4551
f"✅ Collection '{settings.docs_collection_name}' exists with {qdrant_client.get_collection(settings.docs_collection_name).points_count} points. Skipping initialization."

src/sparql_llm/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def get_prefixes_and_schema_for_endpoints(
7272
)
7373
logger.info(f"Fetching {endpoint['endpoint_url']} metadata...")
7474
prefixes_map = get_prefixes_for_endpoint(endpoint["endpoint_url"], endpoint.get("examples_file"), prefixes_map)
75+
# Cache the metadata in a JSON file
7576
with open(ENDPOINTS_METADATA_FILE, "w") as f:
7677
json.dump({"prefixes_map": prefixes_map, "classes_schema": endpoints_void_dict}, f, indent=2)
7778
return prefixes_map, endpoints_void_dict

0 commit comments

Comments
 (0)