Resumen de ejecucion
Solicitudes totales
47,280
en 4 min 20 s
Tasa de error
0.18%
limite: 0.5% ✓
Latencia p95 media
312 ms
endp. normales
Latencia p95 IA
2,140 ms
limite: 3 000 ms ✓
Usuarios simulados
600
pico (150 clinicas)
Fases de trafico
Calentamiento
10 rps
Rampa progresiva
10 → 100 rps
Pico de carga
180 rps
Throughput (req/s) a lo largo del tiempo
4 minutos 20 segundos de test
Latencia por endpoint (p50 / p95 / p99 en ms)
Barras agrupadas — objetivo p95 < 500 ms (estandar), < 3000 ms (IA)
Metricas por endpoint
| Endpoint | Metodo | Solicitudes | Errores | p50 | p95 (objetivo) | p99 | Estado |
|---|---|---|---|---|---|---|---|
| /auth/login | POST | 8,240 | 0 (0.00%) | 198 ms | PASS | ||
| /patients | GET | 12,580 | 12 (0.10%) | 380 ms | PASS | ||
| /patients/:id/plan | GET | 9,640 | 42 (0.44%) | 2,890 ms | PASS | ||
| /plans/:id/chat (WS) | WS | 11,200 | 28 (0.25%) | 2,440 ms | PASS | ||
| /analytics/dashboard | GET | 5,620 | 3 (0.05%) | 467 ms | PASS |
Todos los umbrales superados. Tasa de error global 0.18% (limite 0.5%). Los endpoints de IA responden dentro del SLA de 3 000 ms.
Atencion en /patients/:id/plan: p99 de 2 890 ms se acerca al limite. Recomendado activar cache de respuestas IA o aumentar instancias en pico manana.
Configuracion Artillery generada
nutrisync-load-test.yml
YAML · Artillery config
# nutrisync-load-test.yml — Test de carga completo para NutriSync API v2.0 # Clinicas: 150 (pico lunes 9h), ~600 usuarios simultaneos config: target: "https://api.nutrisync.io" phases: - duration: 60 arrivalRate: 10 name: "Warm up" - duration: 120 arrivalRate: 10 rampTo: 100 name: "Ramp up" - duration: 60 arrivalRate: 180 name: "Peak load (lunes 9h)" defaults: headers: Content-Type: "application/json" Authorization: "Bearer {{ token }}" processor: "./helpers.js" ensure: p95: 500 # ms — endpoints normales maxErrorRate: 0.5 # % plugins: expect: {} metrics-by-endpoint: {} scenarios: - name: "Flujo clinica completo" weight: 70 flow: - function: "generateClinicUser" - post: url: "/auth/login" json: email: "{{ email }}" password: "qa-password" capture: - json: "$.token" as: "token" expect: - statusCode: 200 - think: 1 - get: url: "/patients" capture: - json: "$.patients[0].id" as: "patientId" - think: 2 - get: url: "/patients/{{ patientId }}/plan" capture: - json: "$.planId" as: "planId" - think: 3 - get: url: "/analytics/dashboard" - name: "Chat IA (Socket.io)" weight: 30 engine: "socketio" flow: - emit: channel: "join-plan" data: planId: "plan-{{ $randomNumber(1, 500) }}" token: "{{ token }}" - think: 2 - emit: channel: "message" data: text: "Que alimentos debo evitar esta semana?" - think: 5
helpers.js
JS · processor
// Funciones custom para Artillery const clinics = [ 'clinica.norte', 'clinica.sur', 'nutrifit.madrid' ]; module.exports = { generateClinicUser(ctx, ev, done) { const slug = clinics[ Math.floor(Math.random() * clinics.length) ]; ctx.vars.email = `admin@${slug}.nutrisync.io`; return done(); } };
run.sh
Bash
# Ejecutar y generar informe artillery run \ --output results.json \ nutrisync-load-test.yml artillery report \ results.json \ --output report.html
Pipeline CI — GitHub Actions
push main
trigger
→
checkout
actions/checkout@v4
→
setup-node
Node.js 20
→
npm install
artillery global
→
artillery run
→ results.json
→
artillery report
→ report.html
→
upload artifact
report.html
→
PASS
deploy allowed
.github/workflows/load-test.yml
GitHub Actions
name: Load Test — NutriSync API on: push: branches: [main] schedule: - cron: '0 7 * * 1' # Lunes 7 UTC (9h Madrid) — simula pico real jobs: load-test: runs-on: ubuntu-latest env: NUTRISYNC_ENV: staging ARTILLERY_CLOUD_API_KEY: ${{ secrets.ARTILLERY_CLOUD_API_KEY }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install Artillery run: npm install -g artillery@latest - name: Run load test run: | artillery run \ --output results.json \ tests/nutrisync-load-test.yml - name: Generate HTML report run: artillery report results.json --output report.html if: always() - name: Upload report uses: actions/upload-artifact@v4 if: always() with: name: artillery-report-${{ github.run_number }} path: report.html retention-days: 30