Skip to content

Commit ece3d76

Browse files
Merge branch 'main' into devops
2 parents ad1545f + 50bf8e4 commit ece3d76

File tree

14 files changed

+2351
-272
lines changed

14 files changed

+2351
-272
lines changed

DocsManager/.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ RABBITMQ_PASSWORD=guest
1111
RABBITMQ_HOST=localhost
1212
RABBITMQ_PORT=5672
1313
RABBITMQ_MANAGEMENT_PORT=15672
14+
RABBITMQ_QUEUE_NAME=document.process
15+
RABBITMQ_EXCHANGE_NAME=minio-events
16+
1417

1518
# MinIO Configuration
1619
MINIO_ENDPOINT=localhost:9000
1720
MINIO_ACCESS_KEY=minioadmin
1821
MINIO_SECRET_KEY=minioadmin
1922
MINIO_BUCKET=goland-bucket
23+
MINIO_FOLDER=rag-docs
2024
MINIO_USE_SSL=false
2125

2226
# OpenAI Configuration

DocsManager/app/api/routes/admin.py

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
from app.core.db_connection import get_db
1313
from app.models.document import Document as DocumentModel
1414
from app.services.minio_service import minio_service
15-
from app.core.rabbitmq import rabbitmq
16-
from app.core.config import settings
1715

1816
logger = logging.getLogger(__name__)
1917

@@ -31,10 +29,12 @@ async def upload_document(file: UploadFile = File(...), db: Session = Depends(ge
3129
3230
Flow:
3331
1. Validate file
34-
2. Save to MinIO
32+
2. Save to MinIO (in the folder specified by MINIO_FOLDER)
3533
3. Save metadata to PostgreSQL
36-
4. Publish message to RabbitMQ
37-
5. Return immediate response
34+
4. Return immediate response
35+
36+
Note: MinIO events will automatically publish a message to RabbitMQ
37+
when a file is created in the configured folder.
3838
"""
3939
try:
4040
# 1. Validate file
@@ -105,21 +105,9 @@ async def upload_document(file: UploadFile = File(...), db: Session = Depends(ge
105105
detail=f"Failed to save document metadata: {str(e)}"
106106
)
107107

108-
# 4. Publish message to RabbitMQ (only after successful DB commit)
109-
message = {
110-
"document_id": document_id,
111-
"minio_path": minio_path,
112-
"filename": file.filename,
113-
}
114-
115-
try:
116-
rabbitmq.publish_message(settings.queue_name, message)
117-
except Exception as e:
118-
logger.error(f"Failed to publish message to RabbitMQ: {e}")
119-
# Don't fail the request, but log the error
120-
# The document is already saved, it can be processed manually
121-
122-
# 5. Return response
108+
# 4. Return response
109+
# Note: MinIO events will automatically publish a message to RabbitMQ
110+
# when the file is created in the configured folder
123111
return DocumentUploadResponse(
124112
id=document_id,
125113
filename=file.filename,

DocsManager/app/core/config.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ class Settings(BaseSettings):
2929
minio_access_key: str
3030
minio_secret_key: str
3131
minio_bucket: str = "documents"
32+
minio_folder: str = "rag-docs"
3233
minio_use_ssl: bool = True
3334

3435
# Database Configuration (for SQLAlchemy)
3536
database_url: str = ""
3637

37-
# Application
38-
queue_name: str = "document.process"
38+
# RabbitMQ Queue/Exchange
39+
rabbitmq_queue_name: str = "document.process"
40+
rabbitmq_exchange_name: str = "minio-events"
3941

4042
model_config = SettingsConfigDict(
4143
env_file=".env",
@@ -53,13 +55,6 @@ def normalize_rabbitmq_host(cls, v: str) -> str:
5355
logger.warning("RABBITMQ_HOST is empty, using 'localhost' as default")
5456
return "localhost"
5557

56-
# Replace Docker service name with localhost
57-
if v.strip() == "rabbitmq":
58-
logger.warning(
59-
"RABBITMQ_HOST='rabbitmq' detected. Changing to 'localhost' because app runs outside Docker"
60-
)
61-
return "localhost"
62-
6358
return v
6459

6560
@model_validator(mode='after')

DocsManager/app/core/rabbitmq.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,32 @@ def close(self):
4646
self.connection.close()
4747
logger.info("RabbitMQ connection closed")
4848

49-
def declare_queue(self, queue_name: str, durable: bool = True):
50-
"""Declares a queue"""
49+
def declare_exchange(self, exchange_name: str, exchange_type: str = "direct", durable: bool = True):
50+
"""Declares an exchange"""
51+
if not self.channel:
52+
self.connect()
53+
self.channel.exchange_declare(
54+
exchange=exchange_name,
55+
exchange_type=exchange_type,
56+
durable=durable
57+
)
58+
logger.info(f"Exchange '{exchange_name}' declared")
59+
60+
def declare_queue(self, queue_name: str, exchange_name: str = None, durable: bool = True):
61+
"""Declares a queue and optionally binds it to an exchange"""
5162
if not self.channel:
5263
self.connect()
5364
self.channel.queue_declare(queue=queue_name, durable=durable)
5465
logger.info(f"Queue '{queue_name}' declared")
66+
67+
# Bind to exchange if provided
68+
if exchange_name:
69+
self.channel.queue_bind(
70+
queue=queue_name,
71+
exchange=exchange_name,
72+
routing_key=queue_name
73+
)
74+
logger.info(f"Queue '{queue_name}' bound to exchange '{exchange_name}'")
5575

5676
def publish_message(self, queue_name: str, message: dict):
5777
"""Publishes a message to the queue"""

DocsManager/app/services/minio_service.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ def upload_file(self, file_data: bytes, filename: str, content_type: str = "appl
6666
try:
6767
# Generate a unique name for the file
6868
file_extension = filename.split(".")[-1] if "." in filename else "pdf"
69-
object_name = f"{uuid.uuid4()}.{file_extension}"
69+
# Use MINIO_FOLDER to organize files in a specific folder
70+
folder = settings.minio_folder.rstrip("/") # Remove trailing slash if present
71+
object_name = f"{folder}/{uuid.uuid4()}.{file_extension}"
7072

7173
file_stream = BytesIO(file_data)
7274
file_size = len(file_data)

DocsManager/main.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ async def startup_event():
2525
init_db()
2626
logging.info("Database initialized successfully")
2727

28-
# Initialize RabbitMQ connection (will be used when publishing messages)
28+
# Initialize RabbitMQ connection, exchange and queue
2929
from app.core.rabbitmq import rabbitmq
30-
logging.info("RabbitMQ module loaded")
30+
from app.core.config import settings
31+
rabbitmq.connect()
32+
rabbitmq.declare_exchange(settings.rabbitmq_exchange_name)
33+
rabbitmq.declare_queue(settings.rabbitmq_queue_name, settings.rabbitmq_exchange_name)
34+
logging.info(f"RabbitMQ initialized: exchange='{settings.rabbitmq_exchange_name}', queue='{settings.rabbitmq_queue_name}'")
3135
except Exception as e:
3236
logging.error(f"Failed to initialize services: {e}")
3337
raise

DocsManager/scripts/README.md

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Scripts de Configuración
2+
3+
## Orden de Ejecución
4+
5+
**IMPORTANTE:** Los scripts deben ejecutarse en este orden:
6+
7+
1. **setup_rabbitmq.sh** - Configura RabbitMQ (exchange, queue y binding)
8+
2. **setup_minio_events.sh** - Configura MinIO para enviar eventos a RabbitMQ
9+
10+
## setup_rabbitmq.sh
11+
12+
Script para configurar RabbitMQ con el exchange, queue y binding necesarios para recibir eventos de MinIO.
13+
14+
### Requisitos Previos
15+
16+
1. **rabbitmqadmin instalado** (el script intentará descargarlo automáticamente si no está disponible)
17+
2. **RabbitMQ corriendo** con el plugin de management habilitado
18+
19+
### Uso
20+
21+
```bash
22+
cd DocsManager/scripts
23+
./setup_rabbitmq.sh
24+
```
25+
26+
### Qué hace el script
27+
28+
1. Verifica/descarga `rabbitmqadmin` si no está instalado
29+
2. Crea el exchange `minio-events` (tipo: direct, durable)
30+
3. Crea la queue `document.process` (durable)
31+
4. Crea el binding entre el exchange y la queue
32+
5. Muestra la configuración resultante
33+
34+
## setup_minio_events.sh
35+
36+
Script para configurar eventos de MinIO hacia RabbitMQ. Cuando se crea un archivo en el bucket `goland-bucket` dentro de la carpeta especificada en `MINIO_FOLDER` (por defecto `rag-docs/`), MinIO publicará automáticamente un mensaje en la cola de RabbitMQ.
37+
38+
### Requisitos Previos
39+
40+
1. **MinIO Client (mc) instalado:**
41+
```bash
42+
# macOS
43+
brew install minio/stable/mc
44+
45+
# Linux
46+
wget https://dl.min.io/client/mc/release/linux-amd64/mc
47+
chmod +x mc
48+
sudo mv mc /usr/local/bin/
49+
```
50+
51+
2. **MinIO corriendo** y accesible
52+
3. **RabbitMQ corriendo** y accesible
53+
4. **RabbitMQ ya configurado** (ejecutar `setup_rabbitmq.sh` primero)
54+
55+
### Uso
56+
57+
#### Opción 1: Usando variables de entorno del archivo .env
58+
59+
El script automáticamente carga las variables del archivo `.env` en el directorio raíz de DocsManager:
60+
61+
```bash
62+
cd DocsManager
63+
./scripts/setup_minio_events.sh
64+
```
65+
66+
#### Opción 2: Usando variables de entorno directamente
67+
68+
```bash
69+
export MINIO_ENDPOINT=localhost:9000
70+
export MINIO_ACCESS_KEY=minioadmin
71+
export MINIO_SECRET_KEY=minioadmin
72+
export MINIO_BUCKET=goland-bucket
73+
export MINIO_FOLDER=rag-docs
74+
export RABBITMQ_HOST=rabbitmq
75+
export RABBITMQ_USER=guest
76+
export RABBITMQ_PASSWORD=guest
77+
export QUEUE_NAME=document.process
78+
79+
./scripts/setup_minio_events.sh
80+
```
81+
82+
### Variables de Entorno
83+
84+
El script utiliza las siguientes variables (con valores por defecto):
85+
86+
| Variable | Descripción | Valor por Defecto |
87+
|----------|-------------|-------------------|
88+
| `MINIO_ENDPOINT` | Endpoint de MinIO (host:puerto) | `localhost:9000` |
89+
| `MINIO_ACCESS_KEY` | Clave de acceso de MinIO | `minioadmin` |
90+
| `MINIO_SECRET_KEY` | Clave secreta de MinIO | `minioadmin` |
91+
| `MINIO_BUCKET` | Nombre del bucket | `goland-bucket` |
92+
| `MINIO_FOLDER` | Carpeta dentro del bucket donde se monitorean los eventos | `rag-docs` |
93+
| `MINIO_USE_SSL` | Usar SSL para MinIO | `false` |
94+
| `RABBITMQ_HOST` | Host de RabbitMQ | `rabbitmq` |
95+
| `RABBITMQ_PORT` | Puerto de RabbitMQ | `5672` |
96+
| `RABBITMQ_USER` | Usuario de RabbitMQ | `guest` |
97+
| `RABBITMQ_PASSWORD` | Contraseña de RabbitMQ | `guest` |
98+
| `QUEUE_NAME` | Nombre de la cola | `document.process` |
99+
100+
### Qué hace el script
101+
102+
1. Verifica que `mc` esté instalado
103+
2. Carga variables de entorno desde `.env` (si existe)
104+
3. Configura un alias de MinIO
105+
4. Verifica la conexión a MinIO
106+
5. Crea el bucket si no existe
107+
6. Configura la notificación AMQP hacia RabbitMQ
108+
7. Reinicia MinIO para aplicar cambios
109+
8. Configura eventos para archivos en la carpeta especificada en `MINIO_FOLDER` dentro del bucket
110+
9. Muestra un resumen de la configuración
111+
112+
### Formato del Mensaje
113+
114+
Cuando MinIO detecta un nuevo archivo en la carpeta especificada en `MINIO_FOLDER` (por defecto `rag-docs/`), publica un mensaje JSON en RabbitMQ con el siguiente formato:
115+
116+
```json
117+
{
118+
"EventName": "s3:ObjectCreated:Put",
119+
"Key": "rag-docs/uuid.pdf",
120+
"Records": [
121+
{
122+
"eventVersion": "2.0",
123+
"eventSource": "minio:s3",
124+
"awsRegion": "",
125+
"eventTime": "2025-01-XX...",
126+
"eventName": "s3:ObjectCreated:Put",
127+
"s3": {
128+
"bucket": {
129+
"name": "goland-bucket"
130+
},
131+
"object": {
132+
"key": "rag-docs/uuid.pdf",
133+
"size": 12345
134+
}
135+
}
136+
}
137+
]
138+
}
139+
```
140+
141+
### Verificar la Configuración
142+
143+
Para verificar que los eventos están configurados:
144+
145+
```bash
146+
mc event list myminio/goland-bucket
147+
```
148+
149+
### Solución de Problemas
150+
151+
1. **Error: "mc: command not found"**
152+
- Instala MinIO Client siguiendo las instrucciones en "Requisitos Previos"
153+
154+
2. **Error: "No se pudo conectar a MinIO"**
155+
- Verifica que MinIO esté corriendo
156+
- Verifica que el endpoint y las credenciales sean correctas
157+
- Si MinIO está en Docker, usa `localhost` o el nombre del servicio
158+
159+
3. **Error: "RabbitMQ connection failed"**
160+
- Verifica que RabbitMQ esté corriendo
161+
- Verifica que el host y puerto sean correctos
162+
- Si RabbitMQ está en Docker, usa el nombre del servicio (`rabbitmq`) en lugar de `localhost`
163+
164+
4. **Los eventos no se disparan**
165+
- Verifica que los archivos se suban a la ruta especificada en `MINIO_FOLDER` dentro del bucket
166+
- Verifica que la cola `document.process` exista en RabbitMQ
167+
- Revisa los logs de MinIO para ver si hay errores
168+
169+
### Notas
170+
171+
- El script reinicia MinIO, lo que puede causar una breve interrupción del servicio
172+
- Los eventos solo se disparan para archivos nuevos (PUT), no para actualizaciones
173+
- El prefijo especificado en `MINIO_FOLDER` es obligatorio - los archivos fuera de esta carpeta no generarán eventos
174+
- Por defecto, `MINIO_FOLDER` está configurado como `rag-docs`, pero puedes cambiarlo usando la variable de entorno
175+

0 commit comments

Comments
 (0)