claude-mpm 4.17.0__py3-none-any.whl → 4.18.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (47) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +48 -17
  3. claude_mpm/agents/agent_loader.py +4 -4
  4. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  5. claude_mpm/config/agent_config.py +2 -2
  6. claude_mpm/core/factories.py +1 -1
  7. claude_mpm/core/optimized_agent_loader.py +3 -3
  8. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  9. claude_mpm/models/resume_log.py +340 -0
  10. claude_mpm/services/agents/auto_config_manager.py +1 -1
  11. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  12. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  13. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  14. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  15. claude_mpm/services/agents/local_template_manager.py +1 -1
  16. claude_mpm/services/core/path_resolver.py +1 -1
  17. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  18. claude_mpm/services/mcp_config_manager.py +2 -2
  19. claude_mpm/services/session_manager.py +205 -1
  20. claude_mpm/services/unified/deployment_strategies/local.py +1 -1
  21. claude_mpm/skills/bundled/api-documentation.md +393 -0
  22. claude_mpm/skills/bundled/async-testing.md +571 -0
  23. claude_mpm/skills/bundled/code-review.md +143 -0
  24. claude_mpm/skills/bundled/database-migration.md +199 -0
  25. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  26. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  27. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  28. claude_mpm/skills/bundled/git-workflow.md +414 -0
  29. claude_mpm/skills/bundled/imagemagick.md +204 -0
  30. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  31. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  32. claude_mpm/skills/bundled/pdf.md +141 -0
  33. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  34. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  35. claude_mpm/skills/bundled/security-scanning.md +327 -0
  36. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  37. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  38. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  39. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  40. claude_mpm/skills/bundled/xlsx.md +157 -0
  41. claude_mpm/utils/agent_dependency_loader.py +2 -2
  42. {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.0.dist-info}/METADATA +68 -1
  43. {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.0.dist-info}/RECORD +47 -24
  44. {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.0.dist-info}/WHEEL +0 -0
  45. {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.0.dist-info}/entry_points.txt +0 -0
  46. {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.0.dist-info}/licenses/LICENSE +0 -0
  47. {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1199 @@
1
+ ---
2
+ skill_id: fastapi-local-dev
3
+ skill_version: 0.1.0
4
+ description: Running FastAPI development servers effectively using Uvicorn, managing production deployments with Gunicorn, and avoiding common pitfalls.
5
+ updated_at: 2025-10-30T17:00:00Z
6
+ tags: [fastapi, python, development, server, api]
7
+ ---
8
+
9
+ # FastAPI Local Development Server
10
+
11
+ ## Overview
12
+
13
+ FastAPI is a modern, high-performance Python web framework for building APIs with automatic OpenAPI documentation, type hints, and async support. This skill covers running FastAPI development servers effectively using Uvicorn, managing production deployments with Gunicorn, and avoiding common pitfalls with process managers like PM2.
14
+
15
+ ## When to Use This Skill
16
+
17
+ - Setting up FastAPI development environment with auto-reload
18
+ - Configuring Uvicorn for development and production
19
+ - Troubleshooting file watching and auto-reload issues
20
+ - Managing FastAPI with systemd vs PM2
21
+ - Resolving virtual environment and dependency issues
22
+ - Optimizing worker processes for production
23
+ - Debugging reload failures and import errors
24
+
25
+ ## Quick Start
26
+
27
+ ### Development Server
28
+
29
+ **Basic Uvicorn Development:**
30
+ ```bash
31
+ # Direct uvicorn
32
+ uvicorn main:app --reload
33
+
34
+ # With custom host and port
35
+ uvicorn main:app --reload --host 0.0.0.0 --port 8000
36
+
37
+ # With log level
38
+ uvicorn main:app --reload --log-level debug
39
+ ```
40
+
41
+ **Using Python Module:**
42
+ ```bash
43
+ # From project root
44
+ python -m uvicorn app.main:app --reload
45
+
46
+ # With path specification
47
+ PYTHONPATH=. uvicorn app.main:app --reload
48
+ ```
49
+
50
+ **In Python Code:**
51
+ ```python
52
+ # main.py
53
+ import uvicorn
54
+ from fastapi import FastAPI
55
+
56
+ app = FastAPI()
57
+
58
+ @app.get("/")
59
+ def read_root():
60
+ return {"message": "Hello World"}
61
+
62
+ if __name__ == "__main__":
63
+ uvicorn.run(
64
+ "main:app",
65
+ host="0.0.0.0",
66
+ port=8000,
67
+ reload=True,
68
+ reload_dirs=["./app"]
69
+ )
70
+ ```
71
+
72
+ ### With Gunicorn (Production)
73
+
74
+ **Gunicorn + Uvicorn Workers:**
75
+ ```bash
76
+ # Production server with 4 workers
77
+ gunicorn app.main:app \
78
+ --workers 4 \
79
+ --worker-class uvicorn.workers.UvicornWorker \
80
+ --bind 0.0.0.0:8000 \
81
+ --timeout 120 \
82
+ --graceful-timeout 30
83
+ ```
84
+
85
+ **Gunicorn Configuration File:**
86
+ ```python
87
+ # gunicorn_conf.py
88
+ import multiprocessing
89
+
90
+ # Server socket
91
+ bind = "0.0.0.0:8000"
92
+ backlog = 2048
93
+
94
+ # Worker processes
95
+ workers = multiprocessing.cpu_count() * 2 + 1
96
+ worker_class = "uvicorn.workers.UvicornWorker"
97
+ worker_connections = 1000
98
+ timeout = 120
99
+ keepalive = 5
100
+ graceful_timeout = 30
101
+
102
+ # Logging
103
+ accesslog = "./logs/access.log"
104
+ errorlog = "./logs/error.log"
105
+ loglevel = "info"
106
+ access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
107
+
108
+ # Process naming
109
+ proc_name = "fastapi-app"
110
+
111
+ # Server mechanics
112
+ daemon = False
113
+ pidfile = "./gunicorn.pid"
114
+ preload_app = True
115
+
116
+ # Worker lifecycle
117
+ max_requests = 1000
118
+ max_requests_jitter = 50
119
+ ```
120
+
121
+ Run with config:
122
+ ```bash
123
+ gunicorn -c gunicorn_conf.py app.main:app
124
+ ```
125
+
126
+ ### With Docker
127
+
128
+ **Development Dockerfile:**
129
+ ```dockerfile
130
+ FROM python:3.11-slim
131
+
132
+ WORKDIR /app
133
+
134
+ # Install dependencies
135
+ COPY requirements.txt .
136
+ RUN pip install --no-cache-dir -r requirements.txt
137
+
138
+ COPY . .
139
+
140
+ # Development: auto-reload enabled
141
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
142
+ ```
143
+
144
+ **Production Dockerfile:**
145
+ ```dockerfile
146
+ FROM python:3.11-slim
147
+
148
+ WORKDIR /app
149
+
150
+ # Install dependencies
151
+ COPY requirements.txt .
152
+ RUN pip install --no-cache-dir -r requirements.txt
153
+
154
+ COPY . .
155
+
156
+ # Production: Gunicorn with Uvicorn workers
157
+ CMD ["gunicorn", "app.main:app", \
158
+ "--workers", "4", \
159
+ "--worker-class", "uvicorn.workers.UvicornWorker", \
160
+ "--bind", "0.0.0.0:8000"]
161
+ ```
162
+
163
+ **Docker Compose:**
164
+ ```yaml
165
+ version: '3.8'
166
+
167
+ services:
168
+ api:
169
+ build: .
170
+ ports:
171
+ - "8000:8000"
172
+ volumes:
173
+ - .:/app
174
+ environment:
175
+ - PYTHONUNBUFFERED=1
176
+ - DATABASE_URL=postgresql://user:pass@db:5432/dbname
177
+ command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
178
+ depends_on:
179
+ - db
180
+
181
+ db:
182
+ image: postgres:15-alpine
183
+ environment:
184
+ - POSTGRES_USER=user
185
+ - POSTGRES_PASSWORD=pass
186
+ - POSTGRES_DB=dbname
187
+ ports:
188
+ - "5432:5432"
189
+ volumes:
190
+ - postgres_data:/var/lib/postgresql/data
191
+
192
+ volumes:
193
+ postgres_data:
194
+ ```
195
+
196
+ ## Configuration Patterns
197
+
198
+ ### Uvicorn Auto-Reload Configuration
199
+
200
+ **Command Line Options:**
201
+ ```bash
202
+ uvicorn main:app \
203
+ --reload \ # Enable auto-reload
204
+ --reload-dir ./app \ # Watch specific directory
205
+ --reload-exclude ./tests \ # Exclude directory
206
+ --reload-include '*.py' \ # Watch specific patterns
207
+ --host 0.0.0.0 \ # Listen on all interfaces
208
+ --port 8000 \ # Port
209
+ --log-level info \ # Logging level
210
+ --access-log \ # Enable access logs
211
+ --use-colors # Colored output
212
+ ```
213
+
214
+ **Programmatic Configuration:**
215
+ ```python
216
+ # main.py
217
+ import uvicorn
218
+ from fastapi import FastAPI
219
+
220
+ app = FastAPI()
221
+
222
+ if __name__ == "__main__":
223
+ uvicorn.run(
224
+ "main:app",
225
+ host="0.0.0.0",
226
+ port=8000,
227
+ reload=True,
228
+ reload_dirs=["./app", "./config"],
229
+ reload_excludes=["./tests", "./docs"],
230
+ reload_includes=["*.py", "*.yaml"],
231
+ log_level="info",
232
+ access_log=True,
233
+ workers=1 # Must be 1 for reload mode
234
+ )
235
+ ```
236
+
237
+ ### systemd vs PM2 Comparison
238
+
239
+ **systemd (Recommended for Linux Production):**
240
+
241
+ Advantages:
242
+ - Native OS-level process management
243
+ - Automatic restart on failure
244
+ - System resource limits (CPU, memory)
245
+ - Integrated logging with journald
246
+ - No additional dependencies
247
+ - Better security controls
248
+
249
+ Example systemd service:
250
+ ```ini
251
+ # /etc/systemd/system/fastapi.service
252
+ [Unit]
253
+ Description=FastAPI Application
254
+ After=network.target
255
+
256
+ [Service]
257
+ Type=notify
258
+ User=www-data
259
+ Group=www-data
260
+ WorkingDirectory=/opt/fastapi-app
261
+ Environment="PATH=/opt/fastapi-app/venv/bin"
262
+ ExecStart=/opt/fastapi-app/venv/bin/gunicorn \
263
+ -c /opt/fastapi-app/gunicorn_conf.py \
264
+ app.main:app
265
+
266
+ Restart=always
267
+ RestartSec=10
268
+
269
+ # Security
270
+ NoNewPrivileges=true
271
+ PrivateTmp=true
272
+
273
+ # Resource limits
274
+ LimitNOFILE=65536
275
+ MemoryLimit=2G
276
+
277
+ [Install]
278
+ WantedBy=multi-user.target
279
+ ```
280
+
281
+ Commands:
282
+ ```bash
283
+ sudo systemctl start fastapi
284
+ sudo systemctl enable fastapi
285
+ sudo systemctl status fastapi
286
+ sudo journalctl -u fastapi -f
287
+ ```
288
+
289
+ **PM2 (Cross-Platform Alternative):**
290
+
291
+ Advantages:
292
+ - Works on Windows, macOS, Linux
293
+ - Built-in load balancer
294
+ - Easy monitoring dashboard
295
+ - Simple deployment workflow
296
+
297
+ Disadvantages for Python:
298
+ - Watch mode can break Python imports
299
+ - Less efficient than systemd on Linux
300
+ - Additional Node.js dependency
301
+ - More complex setup for Python
302
+
303
+ **Critical Warning: Never use PM2 watch mode with Python FastAPI applications.**
304
+
305
+ ### PM2 Configuration (Without Watch Mode)
306
+
307
+ ```javascript
308
+ // ecosystem.config.js
309
+ module.exports = {
310
+ apps: [{
311
+ name: 'fastapi-app',
312
+ script: '/opt/fastapi-app/venv/bin/gunicorn',
313
+ args: '-c gunicorn_conf.py app.main:app',
314
+ cwd: '/opt/fastapi-app',
315
+ instances: 1,
316
+ exec_mode: 'fork', // NOT cluster for Python
317
+ autorestart: true,
318
+ max_memory_restart: '1G',
319
+
320
+ // CRITICAL: No watch mode for Python
321
+ watch: false,
322
+
323
+ env: {
324
+ NODE_ENV: 'production',
325
+ PYTHONUNBUFFERED: '1'
326
+ },
327
+
328
+ error_file: './logs/pm2-error.log',
329
+ out_file: './logs/pm2-out.log',
330
+ log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
331
+ merge_logs: true,
332
+
333
+ // Graceful shutdown
334
+ kill_timeout: 5000,
335
+ wait_ready: true,
336
+ listen_timeout: 10000
337
+ }]
338
+ };
339
+ ```
340
+
341
+ **Start with PM2:**
342
+ ```bash
343
+ pm2 start ecosystem.config.js
344
+ pm2 save
345
+ pm2 startup # Enable auto-start on boot
346
+ ```
347
+
348
+ ### Virtual Environment Handling
349
+
350
+ **Activate Virtual Environment:**
351
+ ```bash
352
+ # Create venv
353
+ python -m venv venv
354
+
355
+ # Activate
356
+ source venv/bin/activate # Linux/macOS
357
+ venv\Scripts\activate # Windows
358
+
359
+ # Install dependencies
360
+ pip install -r requirements.txt
361
+
362
+ # Run server
363
+ uvicorn main:app --reload
364
+ ```
365
+
366
+ **Direct Execution (Without Activation):**
367
+ ```bash
368
+ # Use full path to venv python
369
+ ./venv/bin/python -m uvicorn main:app --reload
370
+
371
+ # Or venv uvicorn directly
372
+ ./venv/bin/uvicorn main:app --reload
373
+ ```
374
+
375
+ **In Scripts:**
376
+ ```bash
377
+ #!/bin/bash
378
+ # start-dev.sh
379
+
380
+ # Activate venv and run
381
+ source venv/bin/activate
382
+ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
383
+ ```
384
+
385
+ **Environment Variables for Imports:**
386
+ ```bash
387
+ # Set PYTHONPATH for imports
388
+ PYTHONPATH=/opt/fastapi-app ./venv/bin/uvicorn app.main:app --reload
389
+ ```
390
+
391
+ ### WSL WATCHFILES_FORCE_POLLING
392
+
393
+ **Problem:** File watching doesn't work in WSL (Windows Subsystem for Linux) due to filesystem event limitations.
394
+
395
+ **Solution:** Force polling mode for file changes.
396
+
397
+ ```bash
398
+ # Set environment variable
399
+ export WATCHFILES_FORCE_POLLING=true
400
+
401
+ # Run uvicorn
402
+ uvicorn main:app --reload
403
+
404
+ # Or inline
405
+ WATCHFILES_FORCE_POLLING=true uvicorn main:app --reload
406
+ ```
407
+
408
+ **Permanent Configuration (.bashrc or .zshrc):**
409
+ ```bash
410
+ # Add to shell config
411
+ echo 'export WATCHFILES_FORCE_POLLING=true' >> ~/.bashrc
412
+ source ~/.bashrc
413
+ ```
414
+
415
+ **In Python Code:**
416
+ ```python
417
+ import os
418
+ os.environ['WATCHFILES_FORCE_POLLING'] = 'true'
419
+
420
+ import uvicorn
421
+
422
+ if __name__ == "__main__":
423
+ uvicorn.run("main:app", reload=True)
424
+ ```
425
+
426
+ ### Reload Directory Configuration
427
+
428
+ **Watch Specific Directories:**
429
+ ```bash
430
+ # Single directory
431
+ uvicorn main:app --reload --reload-dir ./app
432
+
433
+ # Multiple directories
434
+ uvicorn main:app --reload \
435
+ --reload-dir ./app \
436
+ --reload-dir ./config \
437
+ --reload-dir ./models
438
+ ```
439
+
440
+ **Exclude Directories:**
441
+ ```bash
442
+ uvicorn main:app --reload \
443
+ --reload-dir ./app \
444
+ --reload-exclude ./app/tests \
445
+ --reload-exclude ./app/migrations
446
+ ```
447
+
448
+ **Include Specific File Patterns:**
449
+ ```bash
450
+ uvicorn main:app --reload \
451
+ --reload-include '*.py' \
452
+ --reload-include '*.yaml' \
453
+ --reload-include '*.json'
454
+ ```
455
+
456
+ **In Code:**
457
+ ```python
458
+ import uvicorn
459
+
460
+ if __name__ == "__main__":
461
+ uvicorn.run(
462
+ "main:app",
463
+ reload=True,
464
+ reload_dirs=["./app", "./config"],
465
+ reload_excludes=["./tests", "./migrations"],
466
+ reload_includes=["*.py", "*.yaml"]
467
+ )
468
+ ```
469
+
470
+ ### Worker Management
471
+
472
+ **Development:** Always use 1 worker with reload.
473
+ ```bash
474
+ uvicorn main:app --reload --workers 1
475
+ ```
476
+
477
+ **Production:** Calculate workers based on CPU cores.
478
+
479
+ **Formula:** `(2 × CPU cores) + 1`
480
+
481
+ ```bash
482
+ # 4 CPU cores = 9 workers
483
+ gunicorn app.main:app \
484
+ --workers 9 \
485
+ --worker-class uvicorn.workers.UvicornWorker
486
+ ```
487
+
488
+ **Dynamic Worker Calculation:**
489
+ ```python
490
+ # gunicorn_conf.py
491
+ import multiprocessing
492
+
493
+ workers = multiprocessing.cpu_count() * 2 + 1
494
+ worker_class = "uvicorn.workers.UvicornWorker"
495
+ ```
496
+
497
+ **Worker Timeout Configuration:**
498
+ ```python
499
+ # gunicorn_conf.py
500
+ timeout = 120 # Worker timeout (seconds)
501
+ graceful_timeout = 30 # Graceful shutdown time
502
+ keepalive = 5 # Keep-alive seconds
503
+ ```
504
+
505
+ ## Framework-Specific Best Practices
506
+
507
+ ### Dependency Injection
508
+
509
+ FastAPI's dependency injection system:
510
+
511
+ ```python
512
+ from fastapi import Depends, FastAPI
513
+ from sqlalchemy.orm import Session
514
+
515
+ app = FastAPI()
516
+
517
+ # Database dependency
518
+ def get_db():
519
+ db = SessionLocal()
520
+ try:
521
+ yield db
522
+ finally:
523
+ db.close()
524
+
525
+ @app.get("/users/{user_id}")
526
+ def read_user(user_id: int, db: Session = Depends(get_db)):
527
+ return db.query(User).filter(User.id == user_id).first()
528
+ ```
529
+
530
+ **Benefit for Development:**
531
+ - Dependencies are reloaded automatically
532
+ - Easy mocking for tests
533
+ - Clean separation of concerns
534
+
535
+ ### Async Operations
536
+
537
+ **Use async for I/O-bound operations:**
538
+
539
+ ```python
540
+ from fastapi import FastAPI
541
+ import httpx
542
+
543
+ app = FastAPI()
544
+
545
+ @app.get("/external")
546
+ async def call_external():
547
+ async with httpx.AsyncClient() as client:
548
+ response = await client.get("https://api.example.com")
549
+ return response.json()
550
+ ```
551
+
552
+ **Mixed sync/async endpoints:**
553
+
554
+ ```python
555
+ # Sync endpoint (blocking)
556
+ @app.get("/sync")
557
+ def sync_endpoint():
558
+ result = blocking_operation()
559
+ return result
560
+
561
+ # Async endpoint (non-blocking)
562
+ @app.get("/async")
563
+ async def async_endpoint():
564
+ result = await async_operation()
565
+ return result
566
+ ```
567
+
568
+ **Worker configuration for async:**
569
+ ```python
570
+ # gunicorn_conf.py
571
+ # Use UvicornWorker for async support
572
+ worker_class = "uvicorn.workers.UvicornWorker"
573
+ ```
574
+
575
+ ### Lifespan Events
576
+
577
+ **Startup and shutdown logic:**
578
+
579
+ ```python
580
+ from contextlib import asynccontextmanager
581
+ from fastapi import FastAPI
582
+
583
+ @asynccontextmanager
584
+ async def lifespan(app: FastAPI):
585
+ # Startup
586
+ print("Starting up...")
587
+ # Initialize database pool, cache connections, etc.
588
+ yield
589
+ # Shutdown
590
+ print("Shutting down...")
591
+ # Close database pool, cleanup resources
592
+
593
+ app = FastAPI(lifespan=lifespan)
594
+ ```
595
+
596
+ **Why important for development:**
597
+ - Clean resource management
598
+ - Proper connection pooling
599
+ - Graceful reload on code changes
600
+
601
+ ### Static Files and Templates
602
+
603
+ **Serve static files:**
604
+
605
+ ```python
606
+ from fastapi import FastAPI
607
+ from fastapi.staticfiles import StaticFiles
608
+
609
+ app = FastAPI()
610
+
611
+ app.mount("/static", StaticFiles(directory="static"), name="static")
612
+ ```
613
+
614
+ **Templates with Jinja2:**
615
+
616
+ ```python
617
+ from fastapi import FastAPI, Request
618
+ from fastapi.templating import Jinja2Templates
619
+
620
+ app = FastAPI()
621
+ templates = Jinja2Templates(directory="templates")
622
+
623
+ @app.get("/")
624
+ def read_root(request: Request):
625
+ return templates.TemplateResponse("index.html", {"request": request})
626
+ ```
627
+
628
+ **Auto-reload includes templates and static files** when using `--reload-dir`.
629
+
630
+ ## Common Problems & Solutions
631
+
632
+ ### Problem 1: Port Already in Use (EADDRINUSE)
633
+
634
+ **Symptoms:**
635
+ ```
636
+ ERROR: [Errno 48] error while attempting to bind on address ('0.0.0.0', 8000): address already in use
637
+ ```
638
+
639
+ **Root Cause:**
640
+ Another process (previous Uvicorn instance, other server, or zombie process) is using port 8000.
641
+
642
+ **Solution:**
643
+
644
+ **Option A: Find and Kill Process**
645
+ ```bash
646
+ # Linux/macOS
647
+ lsof -ti:8000 | xargs kill -9
648
+
649
+ # Alternative with fuser
650
+ fuser -k 8000/tcp
651
+
652
+ # Windows
653
+ netstat -ano | findstr :8000
654
+ taskkill /PID <PID> /F
655
+ ```
656
+
657
+ **Option B: Use Different Port**
658
+ ```bash
659
+ uvicorn main:app --reload --port 8001
660
+ ```
661
+
662
+ **Option C: Cleanup Script**
663
+ ```bash
664
+ #!/bin/bash
665
+ # kill-and-start.sh
666
+
667
+ # Kill any process on port 8000
668
+ lsof -ti:8000 | xargs kill -9 2>/dev/null || true
669
+
670
+ # Wait a moment
671
+ sleep 1
672
+
673
+ # Start server
674
+ uvicorn main:app --reload --port 8000
675
+ ```
676
+
677
+ **Option D: Dynamic Port Selection**
678
+ ```python
679
+ import uvicorn
680
+ import socket
681
+
682
+ def find_free_port():
683
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
684
+ s.bind(('', 0))
685
+ s.listen(1)
686
+ port = s.getsockname()[1]
687
+ return port
688
+
689
+ if __name__ == "__main__":
690
+ port = find_free_port()
691
+ print(f"Starting server on port {port}")
692
+ uvicorn.run("main:app", host="0.0.0.0", port=port, reload=True)
693
+ ```
694
+
695
+ ### Problem 2: Auto-Reload Not Working
696
+
697
+ **Symptoms:**
698
+ - Code changes don't trigger server restart
699
+ - Need to manually restart Uvicorn
700
+ - No "Reload detected" messages in console
701
+
702
+ **Root Cause:**
703
+ Multiple causes: file watching disabled, wrong reload directory, WSL filesystem issues, or PM2 interference.
704
+
705
+ **Solution:**
706
+
707
+ **Step 1: Verify Reload is Enabled**
708
+ ```bash
709
+ # Ensure --reload flag is present
710
+ uvicorn main:app --reload
711
+ ```
712
+
713
+ **Step 2: Check Reload Directories**
714
+ ```bash
715
+ # Explicitly set reload directory
716
+ uvicorn main:app --reload --reload-dir ./app
717
+
718
+ # Include specific file patterns
719
+ uvicorn main:app --reload --reload-include '*.py'
720
+ ```
721
+
722
+ **Step 3: WSL Force Polling**
723
+ ```bash
724
+ # For WSL on Windows
725
+ WATCHFILES_FORCE_POLLING=true uvicorn main:app --reload
726
+ ```
727
+
728
+ **Step 4: Check File Permissions**
729
+ ```bash
730
+ # Ensure files are readable
731
+ chmod -R 644 ./app/*.py
732
+ ```
733
+
734
+ **Step 5: Disable PM2 Watch**
735
+
736
+ If using PM2 (not recommended for dev):
737
+ ```javascript
738
+ // ecosystem.config.js
739
+ module.exports = {
740
+ apps: [{
741
+ name: 'fastapi',
742
+ script: 'venv/bin/uvicorn',
743
+ args: 'main:app --reload',
744
+ watch: false // CRITICAL: must be false
745
+ }]
746
+ };
747
+ ```
748
+
749
+ **Step 6: Verify No Syntax Errors**
750
+
751
+ Syntax errors can break auto-reload:
752
+ ```bash
753
+ # Test import
754
+ python -c "from app.main import app"
755
+ ```
756
+
757
+ **Step 7: Check Uvicorn Version**
758
+ ```bash
759
+ # Update uvicorn
760
+ pip install --upgrade uvicorn[standard]
761
+ ```
762
+
763
+ ### Problem 3: Import Errors After Reload
764
+
765
+ **Symptoms:**
766
+ ```
767
+ ModuleNotFoundError: No module named 'app'
768
+ ImportError: attempted relative import with no known parent package
769
+ ```
770
+
771
+ **Root Cause:**
772
+ Incorrect PYTHONPATH, wrong working directory, or circular imports.
773
+
774
+ **Solution:**
775
+
776
+ **Step 1: Set PYTHONPATH**
777
+ ```bash
778
+ # Add current directory to Python path
779
+ export PYTHONPATH="${PYTHONPATH}:$(pwd)"
780
+ uvicorn app.main:app --reload
781
+
782
+ # Or inline
783
+ PYTHONPATH=. uvicorn app.main:app --reload
784
+ ```
785
+
786
+ **Step 2: Use Python Module Execution**
787
+ ```bash
788
+ # Run as module from project root
789
+ python -m uvicorn app.main:app --reload
790
+ ```
791
+
792
+ **Step 3: Fix Import Paths**
793
+
794
+ Bad:
795
+ ```python
796
+ # Relative import without parent
797
+ from models import User
798
+ ```
799
+
800
+ Good:
801
+ ```python
802
+ # Absolute import
803
+ from app.models import User
804
+
805
+ # Or relative with parent
806
+ from .models import User
807
+ ```
808
+
809
+ **Step 4: Check Directory Structure**
810
+ ```
811
+ fastapi-project/
812
+ ├── app/
813
+ │ ├── __init__.py ← REQUIRED for package
814
+ │ ├── main.py
815
+ │ └── models.py
816
+ ├── requirements.txt
817
+ └── main.py (or run from app.main)
818
+ ```
819
+
820
+ **Step 5: Avoid Circular Imports**
821
+
822
+ Bad:
823
+ ```python
824
+ # a.py
825
+ from b import function_b
826
+
827
+ # b.py
828
+ from a import function_a # Circular!
829
+ ```
830
+
831
+ Good:
832
+ ```python
833
+ # Use dependency injection or delayed imports
834
+ # a.py
835
+ def function_a():
836
+ from b import function_b # Import inside function
837
+ function_b()
838
+ ```
839
+
840
+ ### Problem 4: PM2 Watch Mode Breaks Application
841
+
842
+ **Symptoms:**
843
+ - Application restarts continuously
844
+ - Import errors appear after file changes
845
+ - Worker processes crash unexpectedly
846
+
847
+ **Root Cause:**
848
+ PM2 watch mode interferes with Python's import system and virtual environment, causing module resolution failures.
849
+
850
+ **Solution:**
851
+
852
+ **NEVER use PM2 watch mode with FastAPI/Python applications.**
853
+
854
+ **Wrong:**
855
+ ```javascript
856
+ // ecosystem.config.js
857
+ module.exports = {
858
+ apps: [{
859
+ name: 'fastapi',
860
+ script: 'venv/bin/uvicorn',
861
+ args: 'main:app --reload',
862
+ watch: true, // WRONG - Breaks Python
863
+ ignore_watch: ['logs', '.git']
864
+ }]
865
+ };
866
+ ```
867
+
868
+ **Correct for Development:**
869
+
870
+ Don't use PM2 at all. Use uvicorn directly:
871
+ ```bash
872
+ uvicorn main:app --reload
873
+ ```
874
+
875
+ **Correct for Production:**
876
+
877
+ Use PM2 without watch mode:
878
+ ```javascript
879
+ // ecosystem.config.js
880
+ module.exports = {
881
+ apps: [{
882
+ name: 'fastapi',
883
+ script: 'venv/bin/gunicorn',
884
+ args: '-c gunicorn_conf.py app.main:app',
885
+ watch: false, // Correct - no watch mode
886
+ autorestart: true
887
+ }]
888
+ };
889
+ ```
890
+
891
+ **Alternative: Use systemd for production on Linux.**
892
+
893
+ ### Problem 5: Workers Timing Out Under Load
894
+
895
+ **Symptoms:**
896
+ ```
897
+ [CRITICAL] WORKER TIMEOUT (pid:12345)
898
+ Worker with pid 12345 was terminated due to signal 9
899
+ ```
900
+
901
+ **Root Cause:**
902
+ Worker timeout too short for slow operations, insufficient workers, or blocking operations in async context.
903
+
904
+ **Solution:**
905
+
906
+ **Step 1: Increase Timeout**
907
+ ```python
908
+ # gunicorn_conf.py
909
+ timeout = 300 # 5 minutes for long operations
910
+ graceful_timeout = 60
911
+ ```
912
+
913
+ **Step 2: Optimize Worker Count**
914
+ ```python
915
+ # gunicorn_conf.py
916
+ import multiprocessing
917
+
918
+ # Increase workers for CPU-bound tasks
919
+ workers = multiprocessing.cpu_count() * 2 + 1
920
+
921
+ # Or set explicitly
922
+ workers = 8
923
+ ```
924
+
925
+ **Step 3: Use Async for I/O Operations**
926
+
927
+ Bad (blocks worker):
928
+ ```python
929
+ import requests
930
+
931
+ @app.get("/data")
932
+ def get_data():
933
+ response = requests.get("https://slow-api.com") # Blocks!
934
+ return response.json()
935
+ ```
936
+
937
+ Good (non-blocking):
938
+ ```python
939
+ import httpx
940
+
941
+ @app.get("/data")
942
+ async def get_data():
943
+ async with httpx.AsyncClient() as client:
944
+ response = await client.get("https://slow-api.com")
945
+ return response.json()
946
+ ```
947
+
948
+ **Step 4: Background Tasks**
949
+
950
+ For long-running operations:
951
+ ```python
952
+ from fastapi import BackgroundTasks
953
+
954
+ def process_data(data):
955
+ # Long-running task
956
+ pass
957
+
958
+ @app.post("/process")
959
+ async def trigger_process(background_tasks: BackgroundTasks, data: dict):
960
+ background_tasks.add_task(process_data, data)
961
+ return {"status": "processing"}
962
+ ```
963
+
964
+ **Step 5: Monitor Worker Health**
965
+ ```bash
966
+ # Check worker status
967
+ ps aux | grep gunicorn
968
+
969
+ # Monitor logs
970
+ tail -f logs/error.log
971
+ ```
972
+
973
+ ## Anti-Patterns
974
+
975
+ ### What NOT to Do
976
+
977
+ **1. Never Use PM2 Watch Mode with Python**
978
+ ```javascript
979
+ // WRONG
980
+ module.exports = {
981
+ apps: [{
982
+ script: 'venv/bin/uvicorn',
983
+ watch: true // Breaks Python imports
984
+ }]
985
+ };
986
+ ```
987
+
988
+ Why: PM2 watch triggers restarts that break Python's import system and virtual environment.
989
+
990
+ **2. Don't Use Multiple Workers with --reload**
991
+ ```bash
992
+ # WRONG - reload requires single worker
993
+ uvicorn main:app --reload --workers 4
994
+ ```
995
+
996
+ Reload mode only works with 1 worker. Use multiple workers in production without reload.
997
+
998
+ **3. Don't Run Blocking Operations in Async Endpoints**
999
+ ```python
1000
+ # WRONG
1001
+ @app.get("/data")
1002
+ async def get_data():
1003
+ result = requests.get("https://api.com") # Blocking in async!
1004
+ return result.json()
1005
+ ```
1006
+
1007
+ Use `httpx` or `aiohttp` for async HTTP requests.
1008
+
1009
+ **4. Don't Forget Virtual Environment in Production**
1010
+ ```bash
1011
+ # WRONG - uses system Python
1012
+ uvicorn main:app
1013
+
1014
+ # Correct - uses venv
1015
+ ./venv/bin/uvicorn main:app
1016
+ ```
1017
+
1018
+ **5. Don't Skip Graceful Shutdown**
1019
+ ```python
1020
+ # WRONG - abrupt termination
1021
+ # No cleanup code
1022
+
1023
+ # Correct - graceful shutdown
1024
+ @asynccontextmanager
1025
+ async def lifespan(app: FastAPI):
1026
+ yield
1027
+ # Cleanup: close DB, cache connections
1028
+ await db_pool.close()
1029
+ ```
1030
+
1031
+ **6. Don't Use Development Server in Production**
1032
+ ```bash
1033
+ # WRONG for production
1034
+ uvicorn main:app --reload
1035
+
1036
+ # Correct for production
1037
+ gunicorn app.main:app \
1038
+ --workers 4 \
1039
+ --worker-class uvicorn.workers.UvicornWorker
1040
+ ```
1041
+
1042
+ **7. Don't Ignore Security Headers**
1043
+ ```python
1044
+ # WRONG - no security middleware
1045
+ app = FastAPI()
1046
+
1047
+ # Correct - add security
1048
+ from fastapi.middleware.cors import CORSMiddleware
1049
+ from fastapi.middleware.trustedhost import TrustedHostMiddleware
1050
+
1051
+ app.add_middleware(TrustedHostMiddleware, allowed_hosts=["*.example.com"])
1052
+ ```
1053
+
1054
+ ## Quick Reference
1055
+
1056
+ ### Commands
1057
+
1058
+ ```bash
1059
+ # Development
1060
+ uvicorn main:app --reload # Basic dev server
1061
+ uvicorn main:app --reload --port 8001 # Custom port
1062
+ uvicorn main:app --reload --reload-dir ./app # Watch specific dir
1063
+ python -m uvicorn app.main:app --reload # Module execution
1064
+
1065
+ # WSL
1066
+ WATCHFILES_FORCE_POLLING=true uvicorn main:app --reload
1067
+
1068
+ # Production
1069
+ gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker
1070
+ gunicorn -c gunicorn_conf.py app.main:app
1071
+
1072
+ # Virtual Environment
1073
+ python -m venv venv # Create venv
1074
+ source venv/bin/activate # Activate (Linux/macOS)
1075
+ venv\Scripts\activate # Activate (Windows)
1076
+ ./venv/bin/uvicorn main:app --reload # Direct execution
1077
+
1078
+ # Process Management
1079
+ lsof -ti:8000 | xargs kill -9 # Kill process on port
1080
+ ps aux | grep uvicorn # Find uvicorn processes
1081
+
1082
+ # systemd
1083
+ sudo systemctl start fastapi # Start service
1084
+ sudo systemctl status fastapi # Check status
1085
+ sudo journalctl -u fastapi -f # View logs
1086
+
1087
+ # PM2 (Production Only)
1088
+ pm2 start ecosystem.config.js # Start with PM2
1089
+ pm2 logs fastapi # View logs
1090
+ pm2 restart fastapi # Restart
1091
+ ```
1092
+
1093
+ ### Configuration Templates
1094
+
1095
+ **requirements.txt:**
1096
+ ```
1097
+ fastapi==0.104.1
1098
+ uvicorn[standard]==0.24.0
1099
+ gunicorn==21.2.0
1100
+ python-multipart==0.0.6
1101
+ pydantic==2.5.0
1102
+ pydantic-settings==2.1.0
1103
+ ```
1104
+
1105
+ **Minimal FastAPI App:**
1106
+ ```python
1107
+ # main.py
1108
+ from fastapi import FastAPI
1109
+ import uvicorn
1110
+
1111
+ app = FastAPI()
1112
+
1113
+ @app.get("/")
1114
+ def read_root():
1115
+ return {"message": "Hello World"}
1116
+
1117
+ @app.get("/health")
1118
+ def health_check():
1119
+ return {"status": "healthy"}
1120
+
1121
+ if __name__ == "__main__":
1122
+ uvicorn.run(
1123
+ "main:app",
1124
+ host="0.0.0.0",
1125
+ port=8000,
1126
+ reload=True
1127
+ )
1128
+ ```
1129
+
1130
+ **Production Gunicorn Config:**
1131
+ ```python
1132
+ # gunicorn_conf.py
1133
+ import multiprocessing
1134
+
1135
+ bind = "0.0.0.0:8000"
1136
+ workers = multiprocessing.cpu_count() * 2 + 1
1137
+ worker_class = "uvicorn.workers.UvicornWorker"
1138
+ timeout = 120
1139
+ graceful_timeout = 30
1140
+ keepalive = 5
1141
+ max_requests = 1000
1142
+ max_requests_jitter = 50
1143
+
1144
+ accesslog = "./logs/access.log"
1145
+ errorlog = "./logs/error.log"
1146
+ loglevel = "info"
1147
+ ```
1148
+
1149
+ **systemd Service:**
1150
+ ```ini
1151
+ [Unit]
1152
+ Description=FastAPI Application
1153
+ After=network.target
1154
+
1155
+ [Service]
1156
+ Type=notify
1157
+ User=www-data
1158
+ WorkingDirectory=/opt/fastapi-app
1159
+ Environment="PATH=/opt/fastapi-app/venv/bin"
1160
+ ExecStart=/opt/fastapi-app/venv/bin/gunicorn -c gunicorn_conf.py app.main:app
1161
+ Restart=always
1162
+ RestartSec=10
1163
+
1164
+ [Install]
1165
+ WantedBy=multi-user.target
1166
+ ```
1167
+
1168
+ **PM2 Config (No Watch):**
1169
+ ```javascript
1170
+ module.exports = {
1171
+ apps: [{
1172
+ name: 'fastapi',
1173
+ script: '/opt/fastapi-app/venv/bin/gunicorn',
1174
+ args: '-c gunicorn_conf.py app.main:app',
1175
+ cwd: '/opt/fastapi-app',
1176
+ instances: 1,
1177
+ exec_mode: 'fork',
1178
+ autorestart: true,
1179
+ watch: false, // CRITICAL: never true for Python
1180
+ max_memory_restart: '1G',
1181
+ env: {
1182
+ PYTHONUNBUFFERED: '1'
1183
+ }
1184
+ }]
1185
+ };
1186
+ ```
1187
+
1188
+ ## Related Skills
1189
+
1190
+ - **docker-containerization** - For containerized FastAPI deployments
1191
+ - **systematic-debugging** - For complex debugging scenarios
1192
+ - **express-local-dev** - Similar patterns for Node.js/Express applications
1193
+ - **nextjs-local-dev** - For full-stack applications with Next.js frontend
1194
+
1195
+ ---
1196
+
1197
+ **FastAPI Version Compatibility:** This skill covers FastAPI 0.100+ and Uvicorn 0.20+. For older versions, consult the official FastAPI documentation.
1198
+
1199
+ **Last Updated:** 2024 - Reflects current best practices for FastAPI development and deployment.