Spaces:
Sleeping
Sleeping
sethmcknight
commited on
Commit
·
45cf08e
1
Parent(s):
7e43525
refactor: enhance gunicorn startup script with health checks and config handling
Browse files- Dockerfile +1 -0
- POSTGRES_MIGRATION.md +51 -13
- run.sh +35 -9
Dockerfile
CHANGED
|
@@ -25,6 +25,7 @@ COPY src ./src
|
|
| 25 |
COPY data ./data
|
| 26 |
COPY scripts ./scripts
|
| 27 |
COPY run.sh ./run.sh
|
|
|
|
| 28 |
|
| 29 |
RUN chmod +x run.sh && chmod +x scripts/init_pgvector.py || true
|
| 30 |
|
|
|
|
| 25 |
COPY data ./data
|
| 26 |
COPY scripts ./scripts
|
| 27 |
COPY run.sh ./run.sh
|
| 28 |
+
COPY gunicorn.conf.py ./gunicorn.conf.py
|
| 29 |
|
| 30 |
RUN chmod +x run.sh && chmod +x scripts/init_pgvector.py || true
|
| 31 |
|
POSTGRES_MIGRATION.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
| 1 |
# PostgreSQL Migration Guide
|
| 2 |
|
| 3 |
## Overview
|
|
|
|
| 4 |
This branch implements PostgreSQL with pgvector as an alternative to ChromaDB for vector storage. This reduces memory usage from 400MB+ to ~50-100MB by storing vectors on disk instead of in RAM.
|
| 5 |
|
| 6 |
## What's Been Implemented
|
| 7 |
|
| 8 |
### 1. PostgresVectorService (`src/vector_db/postgres_vector_service.py`)
|
|
|
|
| 9 |
- Full PostgreSQL integration with pgvector extension
|
| 10 |
- Automatic table creation and indexing
|
| 11 |
- Similarity search using cosine distance
|
|
@@ -13,25 +15,30 @@ This branch implements PostgreSQL with pgvector as an alternative to ChromaDB fo
|
|
| 13 |
- Health monitoring and collection info
|
| 14 |
|
| 15 |
### 2. PostgresVectorAdapter (`src/vector_db/postgres_adapter.py`)
|
|
|
|
| 16 |
- Compatibility layer for existing ChromaDB interface
|
| 17 |
- Ensures seamless migration without code changes
|
| 18 |
- Converts between PostgreSQL and ChromaDB result formats
|
| 19 |
|
| 20 |
### 3. Updated Configuration (`src/config.py`)
|
|
|
|
| 21 |
- Added `VECTOR_STORAGE_TYPE` environment variable
|
| 22 |
- PostgreSQL connection settings
|
| 23 |
- Memory optimization parameters
|
| 24 |
|
| 25 |
### 4. Factory Pattern (`src/vector_store/vector_db.py`)
|
|
|
|
| 26 |
- `create_vector_database()` function selects backend automatically
|
| 27 |
- Supports both ChromaDB and PostgreSQL based on configuration
|
| 28 |
|
| 29 |
### 5. Migration Script (`scripts/migrate_to_postgres.py`)
|
|
|
|
| 30 |
- Data optimization (text summarization, metadata cleaning)
|
| 31 |
- Batch processing with memory management
|
| 32 |
- Handles 4GB → 1GB data reduction for free tier
|
| 33 |
|
| 34 |
### 6. Tests (`tests/test_vector_store/test_postgres_vector.py`)
|
|
|
|
| 35 |
- Unit tests with mocked dependencies
|
| 36 |
- Integration tests for real database
|
| 37 |
- Compatibility tests for ChromaDB interface
|
|
@@ -39,15 +46,18 @@ This branch implements PostgreSQL with pgvector as an alternative to ChromaDB fo
|
|
| 39 |
## Setup Instructions
|
| 40 |
|
| 41 |
### Step 1: Create Render PostgreSQL Database
|
|
|
|
| 42 |
1. Go to Render Dashboard
|
| 43 |
2. Create → PostgreSQL
|
| 44 |
3. Choose "Free" plan (1GB storage, 30 days)
|
| 45 |
4. Save the connection details
|
| 46 |
|
| 47 |
### Step 2: Enable pgvector Extension
|
|
|
|
| 48 |
You have several options to enable pgvector:
|
| 49 |
|
| 50 |
**Option A: Use the initialization script (Recommended)**
|
|
|
|
| 51 |
```bash
|
| 52 |
# Set your database URL
|
| 53 |
export DATABASE_URL="postgresql://user:password@host:port/database"
|
|
@@ -58,16 +68,19 @@ python scripts/init_pgvector.py
|
|
| 58 |
|
| 59 |
**Option B: Manual SQL**
|
| 60 |
Connect to your database and run:
|
|
|
|
| 61 |
```sql
|
| 62 |
CREATE EXTENSION IF NOT EXISTS vector;
|
| 63 |
```
|
| 64 |
|
| 65 |
**Option C: From Render Dashboard**
|
|
|
|
| 66 |
1. Go to your PostgreSQL service → Info tab
|
| 67 |
2. Use the "PSQL Command" to connect
|
| 68 |
3. Run: `CREATE EXTENSION IF NOT EXISTS vector;`
|
| 69 |
|
| 70 |
The initialization script (`scripts/init_pgvector.py`) will:
|
|
|
|
| 71 |
- Test database connection
|
| 72 |
- Check PostgreSQL version compatibility (13+)
|
| 73 |
- Install pgvector extension safely
|
|
@@ -75,7 +88,9 @@ The initialization script (`scripts/init_pgvector.py`) will:
|
|
| 75 |
- Provide detailed logging and error messages
|
| 76 |
|
| 77 |
### Step 3: Update Environment Variables
|
|
|
|
| 78 |
Add to your Render environment variables:
|
|
|
|
| 79 |
```bash
|
| 80 |
DATABASE_URL=postgresql://username:password@host:port/database
|
| 81 |
VECTOR_STORAGE_TYPE=postgres
|
|
@@ -83,12 +98,15 @@ MEMORY_LIMIT_MB=400
|
|
| 83 |
```
|
| 84 |
|
| 85 |
### Step 4: Install Dependencies
|
|
|
|
| 86 |
```bash
|
| 87 |
pip install psycopg2-binary==2.9.7
|
| 88 |
```
|
| 89 |
|
| 90 |
### Step 5: Run Migration (Optional)
|
|
|
|
| 91 |
If you have existing ChromaDB data:
|
|
|
|
| 92 |
```bash
|
| 93 |
python scripts/migrate_to_postgres.py --database-url="your-connection-string"
|
| 94 |
```
|
|
@@ -96,12 +114,15 @@ python scripts/migrate_to_postgres.py --database-url="your-connection-string"
|
|
| 96 |
## Usage
|
| 97 |
|
| 98 |
### Switch to PostgreSQL
|
|
|
|
| 99 |
Set environment variable:
|
|
|
|
| 100 |
```bash
|
| 101 |
export VECTOR_STORAGE_TYPE=postgres
|
| 102 |
```
|
| 103 |
|
| 104 |
### Use in Code (No Changes Required!)
|
|
|
|
| 105 |
```python
|
| 106 |
from src.vector_store.vector_db import create_vector_database
|
| 107 |
|
|
@@ -113,22 +134,24 @@ results = vector_db.search(query_embedding, top_k=5)
|
|
| 113 |
|
| 114 |
## Expected Memory Reduction
|
| 115 |
|
| 116 |
-
| Component
|
| 117 |
-
|
| 118 |
-
| Vector Storage
|
| 119 |
-
| Embedding Model
|
| 120 |
-
| Application Code | 50-100MB
|
| 121 |
-
| **Total**
|
| 122 |
|
| 123 |
## Migration Optimizations
|
| 124 |
|
| 125 |
### Data Size Reduction
|
|
|
|
| 126 |
- **Text Summarization**: Documents truncated to 1000 characters
|
| 127 |
- **Metadata Cleaning**: Only essential fields kept
|
| 128 |
- **Dimension Reduction**: Can use smaller embedding models
|
| 129 |
- **Quality Filtering**: Skip very short or low-quality documents
|
| 130 |
|
| 131 |
### Memory Management
|
|
|
|
| 132 |
- **Batch Processing**: Process documents in small batches
|
| 133 |
- **Garbage Collection**: Aggressive cleanup between operations
|
| 134 |
- **Streaming**: Process data without loading everything into memory
|
|
@@ -136,17 +159,20 @@ results = vector_db.search(query_embedding, top_k=5)
|
|
| 136 |
## Testing
|
| 137 |
|
| 138 |
### Unit Tests
|
|
|
|
| 139 |
```bash
|
| 140 |
pytest tests/test_vector_store/test_postgres_vector.py -v
|
| 141 |
```
|
| 142 |
|
| 143 |
### Integration Tests (Requires Database)
|
|
|
|
| 144 |
```bash
|
| 145 |
export TEST_DATABASE_URL="postgresql://test:test@localhost:5432/test_db"
|
| 146 |
pytest tests/test_vector_store/test_postgres_vector.py -m integration -v
|
| 147 |
```
|
| 148 |
|
| 149 |
### Migration Test
|
|
|
|
| 150 |
```bash
|
| 151 |
python scripts/migrate_to_postgres.py --test-only
|
| 152 |
```
|
|
@@ -154,13 +180,17 @@ python scripts/migrate_to_postgres.py --test-only
|
|
| 154 |
## Deployment
|
| 155 |
|
| 156 |
### Local Development
|
|
|
|
| 157 |
Keep using ChromaDB:
|
|
|
|
| 158 |
```bash
|
| 159 |
export VECTOR_STORAGE_TYPE=chroma
|
| 160 |
```
|
| 161 |
|
| 162 |
### Production (Render)
|
|
|
|
| 163 |
Switch to PostgreSQL:
|
|
|
|
| 164 |
```bash
|
| 165 |
export VECTOR_STORAGE_TYPE=postgres
|
| 166 |
export DATABASE_URL="your-render-postgres-url"
|
|
@@ -169,10 +199,13 @@ export DATABASE_URL="your-render-postgres-url"
|
|
| 169 |
## Troubleshooting
|
| 170 |
|
| 171 |
### Common Issues
|
|
|
|
| 172 |
1. **"pgvector extension not found"**
|
|
|
|
| 173 |
- Run `CREATE EXTENSION vector;` in your database
|
| 174 |
|
| 175 |
2. **Connection errors**
|
|
|
|
| 176 |
- Verify DATABASE_URL format: `postgresql://user:pass@host:port/db`
|
| 177 |
- Check firewall/network connectivity
|
| 178 |
|
|
@@ -181,6 +214,7 @@ export DATABASE_URL="your-render-postgres-url"
|
|
| 181 |
- Check that old ChromaDB files aren't being loaded
|
| 182 |
|
| 183 |
### Monitoring
|
|
|
|
| 184 |
```python
|
| 185 |
from src.vector_db.postgres_vector_service import PostgresVectorService
|
| 186 |
|
|
@@ -190,23 +224,27 @@ print(health) # Shows connection status, document count, etc.
|
|
| 190 |
```
|
| 191 |
|
| 192 |
## Rollback Plan
|
|
|
|
| 193 |
If issues occur, simply change back to ChromaDB:
|
|
|
|
| 194 |
```bash
|
| 195 |
export VECTOR_STORAGE_TYPE=chroma
|
| 196 |
```
|
|
|
|
| 197 |
The factory pattern ensures seamless switching between backends.
|
| 198 |
|
| 199 |
## Performance Comparison
|
| 200 |
|
| 201 |
-
| Operation
|
| 202 |
-
|
| 203 |
-
| Insert
|
| 204 |
-
| Search
|
| 205 |
-
| Memory
|
| 206 |
-
| Persistence | File-based | Database
|
| 207 |
-
| Scaling
|
| 208 |
|
| 209 |
## Next Steps
|
|
|
|
| 210 |
1. Test locally with PostgreSQL
|
| 211 |
2. Create Render PostgreSQL database
|
| 212 |
3. Run migration script
|
|
|
|
| 1 |
# PostgreSQL Migration Guide
|
| 2 |
|
| 3 |
## Overview
|
| 4 |
+
|
| 5 |
This branch implements PostgreSQL with pgvector as an alternative to ChromaDB for vector storage. This reduces memory usage from 400MB+ to ~50-100MB by storing vectors on disk instead of in RAM.
|
| 6 |
|
| 7 |
## What's Been Implemented
|
| 8 |
|
| 9 |
### 1. PostgresVectorService (`src/vector_db/postgres_vector_service.py`)
|
| 10 |
+
|
| 11 |
- Full PostgreSQL integration with pgvector extension
|
| 12 |
- Automatic table creation and indexing
|
| 13 |
- Similarity search using cosine distance
|
|
|
|
| 15 |
- Health monitoring and collection info
|
| 16 |
|
| 17 |
### 2. PostgresVectorAdapter (`src/vector_db/postgres_adapter.py`)
|
| 18 |
+
|
| 19 |
- Compatibility layer for existing ChromaDB interface
|
| 20 |
- Ensures seamless migration without code changes
|
| 21 |
- Converts between PostgreSQL and ChromaDB result formats
|
| 22 |
|
| 23 |
### 3. Updated Configuration (`src/config.py`)
|
| 24 |
+
|
| 25 |
- Added `VECTOR_STORAGE_TYPE` environment variable
|
| 26 |
- PostgreSQL connection settings
|
| 27 |
- Memory optimization parameters
|
| 28 |
|
| 29 |
### 4. Factory Pattern (`src/vector_store/vector_db.py`)
|
| 30 |
+
|
| 31 |
- `create_vector_database()` function selects backend automatically
|
| 32 |
- Supports both ChromaDB and PostgreSQL based on configuration
|
| 33 |
|
| 34 |
### 5. Migration Script (`scripts/migrate_to_postgres.py`)
|
| 35 |
+
|
| 36 |
- Data optimization (text summarization, metadata cleaning)
|
| 37 |
- Batch processing with memory management
|
| 38 |
- Handles 4GB → 1GB data reduction for free tier
|
| 39 |
|
| 40 |
### 6. Tests (`tests/test_vector_store/test_postgres_vector.py`)
|
| 41 |
+
|
| 42 |
- Unit tests with mocked dependencies
|
| 43 |
- Integration tests for real database
|
| 44 |
- Compatibility tests for ChromaDB interface
|
|
|
|
| 46 |
## Setup Instructions
|
| 47 |
|
| 48 |
### Step 1: Create Render PostgreSQL Database
|
| 49 |
+
|
| 50 |
1. Go to Render Dashboard
|
| 51 |
2. Create → PostgreSQL
|
| 52 |
3. Choose "Free" plan (1GB storage, 30 days)
|
| 53 |
4. Save the connection details
|
| 54 |
|
| 55 |
### Step 2: Enable pgvector Extension
|
| 56 |
+
|
| 57 |
You have several options to enable pgvector:
|
| 58 |
|
| 59 |
**Option A: Use the initialization script (Recommended)**
|
| 60 |
+
|
| 61 |
```bash
|
| 62 |
# Set your database URL
|
| 63 |
export DATABASE_URL="postgresql://user:password@host:port/database"
|
|
|
|
| 68 |
|
| 69 |
**Option B: Manual SQL**
|
| 70 |
Connect to your database and run:
|
| 71 |
+
|
| 72 |
```sql
|
| 73 |
CREATE EXTENSION IF NOT EXISTS vector;
|
| 74 |
```
|
| 75 |
|
| 76 |
**Option C: From Render Dashboard**
|
| 77 |
+
|
| 78 |
1. Go to your PostgreSQL service → Info tab
|
| 79 |
2. Use the "PSQL Command" to connect
|
| 80 |
3. Run: `CREATE EXTENSION IF NOT EXISTS vector;`
|
| 81 |
|
| 82 |
The initialization script (`scripts/init_pgvector.py`) will:
|
| 83 |
+
|
| 84 |
- Test database connection
|
| 85 |
- Check PostgreSQL version compatibility (13+)
|
| 86 |
- Install pgvector extension safely
|
|
|
|
| 88 |
- Provide detailed logging and error messages
|
| 89 |
|
| 90 |
### Step 3: Update Environment Variables
|
| 91 |
+
|
| 92 |
Add to your Render environment variables:
|
| 93 |
+
|
| 94 |
```bash
|
| 95 |
DATABASE_URL=postgresql://username:password@host:port/database
|
| 96 |
VECTOR_STORAGE_TYPE=postgres
|
|
|
|
| 98 |
```
|
| 99 |
|
| 100 |
### Step 4: Install Dependencies
|
| 101 |
+
|
| 102 |
```bash
|
| 103 |
pip install psycopg2-binary==2.9.7
|
| 104 |
```
|
| 105 |
|
| 106 |
### Step 5: Run Migration (Optional)
|
| 107 |
+
|
| 108 |
If you have existing ChromaDB data:
|
| 109 |
+
|
| 110 |
```bash
|
| 111 |
python scripts/migrate_to_postgres.py --database-url="your-connection-string"
|
| 112 |
```
|
|
|
|
| 114 |
## Usage
|
| 115 |
|
| 116 |
### Switch to PostgreSQL
|
| 117 |
+
|
| 118 |
Set environment variable:
|
| 119 |
+
|
| 120 |
```bash
|
| 121 |
export VECTOR_STORAGE_TYPE=postgres
|
| 122 |
```
|
| 123 |
|
| 124 |
### Use in Code (No Changes Required!)
|
| 125 |
+
|
| 126 |
```python
|
| 127 |
from src.vector_store.vector_db import create_vector_database
|
| 128 |
|
|
|
|
| 134 |
|
| 135 |
## Expected Memory Reduction
|
| 136 |
|
| 137 |
+
| Component | Before (ChromaDB) | After (PostgreSQL) | Savings |
|
| 138 |
+
| ---------------- | ----------------- | -------------------- | ------------- |
|
| 139 |
+
| Vector Storage | 200-300MB | 0MB (disk) | 200-300MB |
|
| 140 |
+
| Embedding Model | 100MB | 50MB (smaller model) | 50MB |
|
| 141 |
+
| Application Code | 50-100MB | 50-100MB | 0MB |
|
| 142 |
+
| **Total** | **350-500MB** | **50-150MB** | **300-350MB** |
|
| 143 |
|
| 144 |
## Migration Optimizations
|
| 145 |
|
| 146 |
### Data Size Reduction
|
| 147 |
+
|
| 148 |
- **Text Summarization**: Documents truncated to 1000 characters
|
| 149 |
- **Metadata Cleaning**: Only essential fields kept
|
| 150 |
- **Dimension Reduction**: Can use smaller embedding models
|
| 151 |
- **Quality Filtering**: Skip very short or low-quality documents
|
| 152 |
|
| 153 |
### Memory Management
|
| 154 |
+
|
| 155 |
- **Batch Processing**: Process documents in small batches
|
| 156 |
- **Garbage Collection**: Aggressive cleanup between operations
|
| 157 |
- **Streaming**: Process data without loading everything into memory
|
|
|
|
| 159 |
## Testing
|
| 160 |
|
| 161 |
### Unit Tests
|
| 162 |
+
|
| 163 |
```bash
|
| 164 |
pytest tests/test_vector_store/test_postgres_vector.py -v
|
| 165 |
```
|
| 166 |
|
| 167 |
### Integration Tests (Requires Database)
|
| 168 |
+
|
| 169 |
```bash
|
| 170 |
export TEST_DATABASE_URL="postgresql://test:test@localhost:5432/test_db"
|
| 171 |
pytest tests/test_vector_store/test_postgres_vector.py -m integration -v
|
| 172 |
```
|
| 173 |
|
| 174 |
### Migration Test
|
| 175 |
+
|
| 176 |
```bash
|
| 177 |
python scripts/migrate_to_postgres.py --test-only
|
| 178 |
```
|
|
|
|
| 180 |
## Deployment
|
| 181 |
|
| 182 |
### Local Development
|
| 183 |
+
|
| 184 |
Keep using ChromaDB:
|
| 185 |
+
|
| 186 |
```bash
|
| 187 |
export VECTOR_STORAGE_TYPE=chroma
|
| 188 |
```
|
| 189 |
|
| 190 |
### Production (Render)
|
| 191 |
+
|
| 192 |
Switch to PostgreSQL:
|
| 193 |
+
|
| 194 |
```bash
|
| 195 |
export VECTOR_STORAGE_TYPE=postgres
|
| 196 |
export DATABASE_URL="your-render-postgres-url"
|
|
|
|
| 199 |
## Troubleshooting
|
| 200 |
|
| 201 |
### Common Issues
|
| 202 |
+
|
| 203 |
1. **"pgvector extension not found"**
|
| 204 |
+
|
| 205 |
- Run `CREATE EXTENSION vector;` in your database
|
| 206 |
|
| 207 |
2. **Connection errors**
|
| 208 |
+
|
| 209 |
- Verify DATABASE_URL format: `postgresql://user:pass@host:port/db`
|
| 210 |
- Check firewall/network connectivity
|
| 211 |
|
|
|
|
| 214 |
- Check that old ChromaDB files aren't being loaded
|
| 215 |
|
| 216 |
### Monitoring
|
| 217 |
+
|
| 218 |
```python
|
| 219 |
from src.vector_db.postgres_vector_service import PostgresVectorService
|
| 220 |
|
|
|
|
| 224 |
```
|
| 225 |
|
| 226 |
## Rollback Plan
|
| 227 |
+
|
| 228 |
If issues occur, simply change back to ChromaDB:
|
| 229 |
+
|
| 230 |
```bash
|
| 231 |
export VECTOR_STORAGE_TYPE=chroma
|
| 232 |
```
|
| 233 |
+
|
| 234 |
The factory pattern ensures seamless switching between backends.
|
| 235 |
|
| 236 |
## Performance Comparison
|
| 237 |
|
| 238 |
+
| Operation | ChromaDB | PostgreSQL | Notes |
|
| 239 |
+
| ----------- | ---------- | ---------- | ---------------------- |
|
| 240 |
+
| Insert | Fast | Medium | Network overhead |
|
| 241 |
+
| Search | Very Fast | Fast | pgvector is optimized |
|
| 242 |
+
| Memory | High | Low | Vectors stored on disk |
|
| 243 |
+
| Persistence | File-based | Database | More reliable |
|
| 244 |
+
| Scaling | Limited | Excellent | Can upgrade storage |
|
| 245 |
|
| 246 |
## Next Steps
|
| 247 |
+
|
| 248 |
1. Test locally with PostgreSQL
|
| 249 |
2. Create Render PostgreSQL database
|
| 250 |
3. Run migration script
|
run.sh
CHANGED
|
@@ -25,16 +25,24 @@ done
|
|
| 25 |
echo "Starting gunicorn on port ${PORT_VALUE} with ${WORKERS_VALUE} workers and timeout ${TIMEOUT_VALUE}s"
|
| 26 |
export PYTHONPATH="/app${PYTHONPATH:+:$PYTHONPATH}"
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
# Start gunicorn in background so we can trap signals and collect diagnostics
|
| 29 |
gunicorn \
|
| 30 |
--bind 0.0.0.0:${PORT_VALUE} \
|
| 31 |
--workers "${WORKERS_VALUE}" \
|
| 32 |
--timeout "${TIMEOUT_VALUE}" \
|
| 33 |
-
--log-level
|
| 34 |
--access-logfile - \
|
| 35 |
--error-logfile - \
|
| 36 |
--capture-output \
|
| 37 |
-
|
| 38 |
app:app &
|
| 39 |
|
| 40 |
GUNICORN_PID=$!
|
|
@@ -55,18 +63,36 @@ handle_term() {
|
|
| 55 |
}
|
| 56 |
trap 'handle_term' SIGTERM SIGINT
|
| 57 |
|
| 58 |
-
#
|
| 59 |
-
echo "Waiting for
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
-
# Pre-warm
|
| 63 |
-
echo "Pre-warming application..."
|
| 64 |
curl -sS -X POST http://localhost:${PORT_VALUE}/chat \
|
| 65 |
-H "Content-Type: application/json" \
|
| 66 |
-d '{"message":"pre-warm"}' \
|
| 67 |
-
--max-time
|
| 68 |
|
| 69 |
-
echo "Server is running."
|
| 70 |
|
| 71 |
# Wait for gunicorn to exit and forward its exit code
|
| 72 |
wait "${GUNICORN_PID}"
|
|
|
|
| 25 |
echo "Starting gunicorn on port ${PORT_VALUE} with ${WORKERS_VALUE} workers and timeout ${TIMEOUT_VALUE}s"
|
| 26 |
export PYTHONPATH="/app${PYTHONPATH:+:$PYTHONPATH}"
|
| 27 |
|
| 28 |
+
# Determine gunicorn config usage
|
| 29 |
+
GUNICORN_CONFIG_ARG=""
|
| 30 |
+
if [ -f gunicorn.conf.py ]; then
|
| 31 |
+
GUNICORN_CONFIG_ARG="--config gunicorn.conf.py"
|
| 32 |
+
else
|
| 33 |
+
echo "Warning: gunicorn.conf.py not found; starting with inline CLI options only."
|
| 34 |
+
fi
|
| 35 |
+
|
| 36 |
# Start gunicorn in background so we can trap signals and collect diagnostics
|
| 37 |
gunicorn \
|
| 38 |
--bind 0.0.0.0:${PORT_VALUE} \
|
| 39 |
--workers "${WORKERS_VALUE}" \
|
| 40 |
--timeout "${TIMEOUT_VALUE}" \
|
| 41 |
+
--log-level info \
|
| 42 |
--access-logfile - \
|
| 43 |
--error-logfile - \
|
| 44 |
--capture-output \
|
| 45 |
+
${GUNICORN_CONFIG_ARG} \
|
| 46 |
app:app &
|
| 47 |
|
| 48 |
GUNICORN_PID=$!
|
|
|
|
| 63 |
}
|
| 64 |
trap 'handle_term' SIGTERM SIGINT
|
| 65 |
|
| 66 |
+
# Readiness probe loop
|
| 67 |
+
echo "Waiting for application readiness (health endpoint)..."
|
| 68 |
+
READY_TIMEOUT="${READY_TIMEOUT:-60}" # total seconds to wait
|
| 69 |
+
READY_INTERVAL="${READY_INTERVAL:-3}" # seconds between checks
|
| 70 |
+
ELAPSED=0
|
| 71 |
+
READY=0
|
| 72 |
+
while [ "$ELAPSED" -lt "$READY_TIMEOUT" ]; do
|
| 73 |
+
if ! kill -0 "${GUNICORN_PID}" 2>/dev/null; then
|
| 74 |
+
echo "Gunicorn process exited prematurely during startup; aborting." >&2
|
| 75 |
+
exit 1
|
| 76 |
+
fi
|
| 77 |
+
if curl -fsS "http://localhost:${PORT_VALUE}/health" >/dev/null 2>&1; then
|
| 78 |
+
READY=1
|
| 79 |
+
break
|
| 80 |
+
fi
|
| 81 |
+
sleep "$READY_INTERVAL"
|
| 82 |
+
ELAPSED=$((ELAPSED + READY_INTERVAL))
|
| 83 |
+
done
|
| 84 |
+
if [ "$READY" -ne 1 ]; then
|
| 85 |
+
echo "Health endpoint not ready after ${READY_TIMEOUT}s; continuing but marking as degraded." >&2
|
| 86 |
+
fi
|
| 87 |
|
| 88 |
+
# Pre-warm (chat) if health is ready
|
| 89 |
+
echo "Pre-warming application via /chat endpoint..."
|
| 90 |
curl -sS -X POST http://localhost:${PORT_VALUE}/chat \
|
| 91 |
-H "Content-Type: application/json" \
|
| 92 |
-d '{"message":"pre-warm"}' \
|
| 93 |
+
--max-time 30 --fail >/dev/null 2>&1 || echo "Pre-warm request failed but continuing..."
|
| 94 |
|
| 95 |
+
echo "Server is running (PID ${GUNICORN_PID})."
|
| 96 |
|
| 97 |
# Wait for gunicorn to exit and forward its exit code
|
| 98 |
wait "${GUNICORN_PID}"
|