feat: vCPU 및 대역폭 기반 서버 필터링 추가

- minVcpu: expected_users / vcpu_per_users 기반 최소 vCPU 필터링
- 대역폭 기반 provider 필터링:
  - very_heavy (>6TB/month): Linode만 표시
  - heavy (2-6TB/month): Linode 우선 정렬
- queryCandidateServers에 minVcpu, bandwidthEstimate 파라미터 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-25 09:52:51 +09:00
parent 4cb9da06dc
commit fd29ee7557

View File

@@ -720,8 +720,26 @@ async function handleRecommend(
? Math.max(...memoryIntensiveSpecs.map(s => s.min_memory_mb))
: undefined;
// Phase 2: Query candidate servers (depends on minMemoryMb)
const candidates = await queryCandidateServers(env.DB, body, minMemoryMb, lang);
// Calculate minimum vCPU based on expected users and tech specs
// Formula: expected_users / vcpu_per_users (use minimum ratio from all tech specs)
let minVcpu: number | undefined;
if (techSpecs.length > 0) {
const vcpuRequirements = techSpecs.map(spec => {
// Use vcpu_per_users: 1 vCPU can handle N users
// So for expected_users, we need: expected_users / vcpu_per_users vCPUs
const vcpuNeeded = Math.ceil(body.expected_users / spec.vcpu_per_users);
return vcpuNeeded;
});
minVcpu = Math.max(...vcpuRequirements, 1); // At least 1 vCPU
console.log(`[Recommend] Minimum vCPU required: ${minVcpu} (for ${body.expected_users} users)`);
}
// Calculate bandwidth estimate for provider filtering
const bandwidthEstimate = estimateBandwidth(body.expected_users, body.use_case, body.traffic_pattern);
console.log(`[Recommend] Bandwidth estimate: ${bandwidthEstimate.monthly_tb >= 1 ? bandwidthEstimate.monthly_tb + ' TB' : bandwidthEstimate.monthly_gb + ' GB'}/month (${bandwidthEstimate.category})`);
// Phase 2: Query candidate servers (depends on minMemoryMb, minVcpu, bandwidth)
const candidates = await queryCandidateServers(env.DB, body, minMemoryMb, minVcpu, bandwidthEstimate, lang);
console.log('[Recommend] Candidate servers:', candidates.length);
if (candidates.length === 0) {
@@ -904,12 +922,16 @@ function escapeLikePattern(pattern: string): string {
/**
* Query candidate servers from database
* @param minMemoryMb - Minimum memory requirement from tech specs (optional)
* @param minVcpu - Minimum vCPU requirement based on expected users (optional)
* @param bandwidthEstimate - Bandwidth estimate for provider prioritization (optional)
* @param lang - Language for currency selection: 'ko' → KRW, others → retail USD
*/
async function queryCandidateServers(
db: D1Database,
req: RecommendRequest,
minMemoryMb?: number,
minVcpu?: number,
bandwidthEstimate?: BandwidthEstimate,
lang: string = 'en'
): Promise<Server[]> {
// Select price column based on language
@@ -961,6 +983,28 @@ async function queryCandidateServers(
console.log(`[Candidates] Filtering by minimum memory: ${minMemoryMb}MB (${(minMemoryMb/1024).toFixed(1)}GB)`);
}
// Filter by minimum vCPU requirement (from expected users + tech specs)
if (minVcpu && minVcpu > 0) {
query += ` AND it.vcpu >= ?`;
params.push(minVcpu);
console.log(`[Candidates] Filtering by minimum vCPU: ${minVcpu}`);
}
// Provider filtering based on bandwidth requirements
// Heavy bandwidth (>2TB/month) → Linode only (better bandwidth allowance)
// Very heavy bandwidth (>6TB/month) → Linode only with warning
if (bandwidthEstimate) {
if (bandwidthEstimate.category === 'very_heavy') {
// >6TB/month: Linode only (includes up to 20TB depending on plan)
query += ` AND p.id = 1`; // Linode only
console.log(`[Candidates] Very heavy bandwidth (${bandwidthEstimate.monthly_tb}TB/month): Linode only`);
} else if (bandwidthEstimate.category === 'heavy') {
// 2-6TB/month: Prefer Linode, but allow Vultr
// Order by Linode first (handled in ORDER BY)
console.log(`[Candidates] Heavy bandwidth (${bandwidthEstimate.monthly_tb}TB/month): Linode preferred`);
}
}
// Country name to code mapping for common names
// Note: Use specific city names to avoid LIKE pattern collisions (e.g., 'de' matches 'Delhi')
const countryNameToCode: Record<string, string[]> = {
@@ -1035,7 +1079,11 @@ async function queryCandidateServers(
}
// Group by instance + region to show each server per region
query += ` GROUP BY it.id, r.id ORDER BY monthly_price ASC LIMIT 50`;
// For heavy bandwidth, prioritize Linode (p.id=1) over Vultr (p.id=2)
const orderByClause = bandwidthEstimate?.category === 'heavy'
? `ORDER BY CASE WHEN p.id = 1 THEN 0 ELSE 1 END, monthly_price ASC`
: `ORDER BY monthly_price ASC`;
query += ` GROUP BY it.id, r.id ${orderByClause} LIMIT 50`;
const result = await db.prepare(query).bind(...params).all();