mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-18 01:29:40 +02:00
feat: GPU offload, signup limit, load tests & capacity planning
- Route all AI workloads (Ollama, STT, TTS, Image Gen) to GPU server (192.168.178.11) via LAN instead of host.docker.internal - Upgrade default model to gemma3:12b and max concurrent to 5 - Add daily signup limit service (MAX_DAILY_SIGNUPS env var) - Add GET /api/v1/auth/signup-status public endpoint - Add k6 load test suite (web-apps, auth, sync-websocket, ollama) - Add capacity planning documentation - Fix: add eslint-config to sveltekit-base and calendar Dockerfiles Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
16367384c7
commit
9276d9a212
12 changed files with 683 additions and 14 deletions
81
load-tests/auth-api.js
Normal file
81
load-tests/auth-api.js
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/* eslint-disable no-undef */
|
||||
import http from 'k6/http';
|
||||
import { check, sleep, group } from 'k6';
|
||||
import { Rate, Counter } from 'k6/metrics';
|
||||
|
||||
const errorRate = new Rate('errors');
|
||||
const signupBlocked = new Counter('signup_blocked');
|
||||
|
||||
const AUTH_URL = __ENV.AUTH_URL || 'http://localhost:3001';
|
||||
|
||||
export const options = {
|
||||
stages: [
|
||||
{ duration: '30s', target: 5 },
|
||||
{ duration: '2m', target: 20 },
|
||||
{ duration: '30s', target: 0 },
|
||||
],
|
||||
thresholds: {
|
||||
http_req_duration: ['p(95)<3000'],
|
||||
errors: ['rate<0.10'],
|
||||
},
|
||||
};
|
||||
|
||||
// Generate unique test emails
|
||||
function testEmail(vuId, iter) {
|
||||
return `loadtest_vu${vuId}_${iter}_${Date.now()}@test.invalid`;
|
||||
}
|
||||
|
||||
export default function () {
|
||||
// Weighted random: 70% health, 20% login attempts, 10% register
|
||||
const roll = Math.random();
|
||||
|
||||
if (roll < 0.7) {
|
||||
// Health check — lightweight, tests baseline
|
||||
group('health', () => {
|
||||
const res = http.get(`${AUTH_URL}/health`);
|
||||
const ok = check(res, {
|
||||
'health 200': (r) => r.status === 200,
|
||||
});
|
||||
errorRate.add(!ok);
|
||||
});
|
||||
} else if (roll < 0.9) {
|
||||
// Login attempt with invalid credentials — tests lockout + DB
|
||||
group('login', () => {
|
||||
const res = http.post(
|
||||
`${AUTH_URL}/api/v1/auth/login`,
|
||||
JSON.stringify({
|
||||
email: 'loadtest@nonexistent.invalid',
|
||||
password: 'wrongpassword',
|
||||
}),
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
const ok = check(res, {
|
||||
'login returns 401 or 429': (r) => r.status === 401 || r.status === 429,
|
||||
});
|
||||
errorRate.add(!ok);
|
||||
});
|
||||
} else {
|
||||
// Registration — tests signup limit
|
||||
group('register', () => {
|
||||
const email = testEmail(__VU, __ITER);
|
||||
const res = http.post(
|
||||
`${AUTH_URL}/api/v1/auth/register`,
|
||||
JSON.stringify({
|
||||
email: email,
|
||||
password: 'TestPassword123!',
|
||||
name: `Load Test ${__VU}`,
|
||||
}),
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
const ok = check(res, {
|
||||
'register returns 200 or 429': (r) => r.status === 200 || r.status === 429,
|
||||
});
|
||||
if (res.status === 429) {
|
||||
signupBlocked.add(1);
|
||||
}
|
||||
errorRate.add(!ok);
|
||||
});
|
||||
}
|
||||
|
||||
sleep(Math.random() * 1.5 + 0.5);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue