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:
54
src/index.ts
54
src/index.ts
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user