Đội ngũ HolySheep AI từng triển khai hàng chục ứng dụng desktop sử dụng AI. Bài viết này chia sẻ playbook di chuyển từ relay API chậm và đắt đỏ sang HolySheep — giảm 85% chi phí, độ trễ dưới 50ms. Tất cả code mẫu đều chạy được ngay, có benchmark thực tế và chiến lược rollback nếu cần.

Tại sao di chuyển từ Relay sang HolySheep?

Sau 6 tháng vận hành ứng dụng Electron tích hợp AI cho khách hàng doanh nghiệp, đội ngũ gặp ba vấn đề nghiêm trọng với relay API:

HolySheep cung cấp base_url https://api.holysheep.ai/v1 với tỷ giá ¥1=$1 (tiết kiệm 85%+ so với tính USD thuần), hỗ trợ thanh toán WeChat/Alipay, và cam kết độ trễ dưới 50ms. Đăng ký tại đây để nhận tín dụng miễn phí khi bắt đầu.

Kiến trúc Ứng dụng Electron + AI

Trước khi đi vào code, hiểu rõ kiến trúc giúp tránh rủi ro khi di chuyển:

┌─────────────────────────────────────────────────────────┐
│                    Electron Renderer                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │   React UI   │  │  IPC Bridge  │  │  State Mgmt  │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  │
└────────────────────────────┬────────────────────────────┘
                             │ IPC
┌────────────────────────────┴────────────────────────────┐
│                     Electron Main                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │ API Service │  │ Rate Limiter│  │  Cache Layer │  │
│  │ (HolySheep) │  │             │  │  (Redis)     │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  │
└─────────────────────────────────────────────────────────┘

Setup Dự án Electron với HolySheep

Cài đặt dependencies cần thiết:

npm init -y
npm install [email protected] [email protected]
npm install [email protected]
npm install [email protected]
npm install [email protected]

Dev dependencies

npm install --save-dev [email protected] @electron/[email protected]

Cấu trúc thư mục dự án:

electron-ai-app/
├── src/
│   ├── main/
│   │   ├── index.ts          # Electron main process
│   │   ├── api/
│   │   │   ├── holysheep.ts  # HolySheep API wrapper
│   │   │   └── cache.ts      # Response caching
│   │   └── utils/
│   │       └── logger.ts     # Winston logger
│   └── preload/
│       └── preload.ts        # Context bridge
├── src-renderer/
│   ├── App.tsx               # React entry
│   ├── components/
│   │   ├── ChatBox.tsx
│   │   └── Settings.tsx
│   └── hooks/
│       └── useAI.ts          # AI hook
├── package.json
└── electron-builder.yml

HolySheep API Service — Code thực chiến

Đây là core service kết nối HolySheep. Base URL bắt buộc: https://api.holysheep.ai/v1.

// src/main/api/holysheep.ts
import OpenAI from 'openai';
import { app } from 'electron';
import Store from 'electron-store';

const store = new Store({
  name: 'holysheep-config',
  defaults: {
    apiKey: '',
    baseUrl: 'https://api.holysheep.ai/v1',
    model: 'gpt-4.1',
    maxTokens: 4096,
    temperature: 0.7
  }
});

export interface AIRequest {
  messages: Array<{
    role: 'system' | 'user' | 'assistant';
    content: string;
  }>;
  model?: string;
  temperature?: number;
  max_tokens?: number;
  stream?: boolean;
}

export interface AIResponse {
  content: string;
  usage: {
    prompt_tokens: number;
    completion_tokens: number;
    total_tokens: number;
  };
  model: string;
  latency_ms: number;
}

class HolySheepService {
  private client: OpenAI;
  private requestLog: Array<{ timestamp: number; model: string; latency: number }> = [];

  constructor() {
    const apiKey = store.get('apiKey') as string;
    
    if (!apiKey) {
      throw new Error('HolySheep API key chưa được cấu hình. Vui lòng cài đặt trong Settings.');
    }

    this.client = new OpenAI({
      apiKey: apiKey,
      baseURL: store.get('baseUrl') as string
    });
  }

  async chat(request: AIRequest): Promise {
    const startTime = Date.now();
    
    try {
      const completion = await this.client.chat.completions.create({
        model: request.model || store.get('model') as string,
        messages: request.messages,
        temperature: request.temperature || store.get('temperature') as number,
        max_tokens: request.max_tokens || store.get('maxTokens') as number,
        stream: false
      });

      const latency_ms = Date.now() - startTime;

      this.logRequest(completion.model || request.model || 'unknown', latency_ms);

      return {
        content: completion.choices[0]?.message?.content || '',
        usage: {
          prompt_tokens: completion.usage?.prompt_tokens || 0,
          completion_tokens: completion.usage?.completion_tokens || 0,
          total_tokens: completion.usage?.total_tokens || 0
        },
        model: completion.model || request.model || 'unknown',
        latency_ms
      };
    } catch (error: any) {
      this.handleError(error);
      throw error;
    }
  }

  async chatStream(
    request: AIRequest,
    onChunk: (content: string) => void
  ): Promise<AIResponse> {
    const startTime = Date.now();
    let fullContent = '';

    try {
      const stream = await this.client.chat.completions.create({
        model: request.model || store.get('model') as string,
        messages: request.messages,
        temperature: request.temperature || store.get('temperature') as number,
        max_tokens: request.max_tokens || store.get('maxTokens') as number,
        stream: true
      });

      for await (const chunk of stream) {
        const content = chunk.choices[0]?.delta?.content || '';
        if (content) {
          fullContent += content;
          onChunk(content);
        }
      }

      const latency_ms = Date.now() - startTime;
      this.logRequest(request.model || 'unknown', latency_ms);

      return {
        content: fullContent,
        usage: {
          prompt_tokens: 0,
          completion_tokens: 0,
          total_tokens: 0
        },
        model: request.model || 'unknown',
        latency_ms
      };
    } catch (error: any) {
      this.handleError(error);
      throw error;
    }
  }

  private logRequest(model: string, latency: number): void {
    this.requestLog.push({ timestamp: Date.now(), model, latency });
    
    // Keep last 100 requests for analytics
    if (this.requestLog.length > 100) {
      this.requestLog.shift();
    }

    // Log performance metrics
    console.log([HolySheep] ${model} - ${latency}ms);
  }

  private handleError(error: any): never {
    if (error.status === 401) {
      throw new Error('API key không hợp lệ. Vui lòng kiểm tra lại trong Settings.');
    }
    if (error.status === 429) {
      throw new Error('Rate limit exceeded. Vui lòng thử lại sau.');
    }
    if (error.code === 'ECONNREFUSED') {
      throw new Error('Không thể kết nối HolySheep API. Kiểm tra kết nối mạng.');
    }
    throw error;
  }

  getStats(): { avgLatency: number; totalRequests: number } {
    if (this.requestLog.length === 0) {
      return { avgLatency: 0, totalRequests: 0 };
    }

    const totalLatency = this.requestLog.reduce((sum, r) => sum + r.latency, 0);
    return {
      avgLatency: Math.round(totalLatency / this.requestLog.length),
      totalRequests: this.requestLog.length
    };
  }
}

export const holySheepService = new HolySheepService();
export { store };

Electron Main Process — IPC Handler

Main process xử lý IPC từ renderer, quản lý lifecycle và gọi HolySheep API:

// src/main/index.ts
import { app, BrowserWindow, ipcMain } from 'electron';
import * as path from 'path';
import { holySheepService, store } from './api/holysheep';
import { logger } from './utils/logger';

let mainWindow: BrowserWindow | null = null;

function createWindow(): void {
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    minWidth: 800,
    minHeight: 600,
    webPreferences: {
      preload: path.join(__dirname, '../preload/preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
      sandbox: true
    },
    titleBarStyle: 'hiddenInset',
    backgroundColor: '#0a0a0a',
    show: false
  });

  // Show window when ready to prevent flash
  mainWindow.once('ready-to-show', () => {
    mainWindow?.show();
    logger.info('Main window displayed');
  });

  // Load renderer
  if (process.env.NODE_ENV === 'development') {
    mainWindow.loadURL('http://localhost:3000');
    mainWindow.webContents.openDevTools();
  } else {
    mainWindow.loadFile(path.join(__dirname, '../../dist-renderer/index.html'));
  }

  mainWindow.on('closed', () => {
    mainWindow = null;
  });
}

// IPC Handlers
function setupIpcHandlers(): void {
  // AI Chat - Non-streaming
  ipcMain.handle('ai:chat', async (_event, request) => {
    try {
      logger.info(AI Chat request: model=${request.model || 'default'});
      const response = await holySheepService.chat(request);
      logger.info(AI Chat response: ${response.latency_ms}ms, ${response.usage.total_tokens} tokens);
      return { success: true, data: response };
    } catch (error: any) {
      logger.error(AI Chat error: ${error.message});
      return { success: false, error: error.message };
    }
  });

  // AI Chat - Streaming
  ipcMain.handle('ai:chatStream', async (event, request) => {
    try {
      let fullContent = '';
      
      await holySheepService.chatStream(request, (chunk) => {
        fullContent += chunk;
        // Send chunk to renderer
        event.sender.send('ai:streamChunk', chunk);
      });

      return { success: true, data: { content: fullContent } };
    } catch (error: any) {
      logger.error(AI Stream error: ${error.message});
      event.sender.send('ai:streamError', error.message);
      return { success: false, error: error.message };
    }
  });

  // Settings
  ipcMain.handle('settings:get', () => {
    return {
      apiKey: store.get('apiKey') ? '***' + (store.get('apiKey') as string).slice(-4) : '',
      baseUrl: store.get('baseUrl'),
      model: store.get('model'),
      maxTokens: store.get('maxTokens'),
      temperature: store.get('temperature')
    };
  });

  ipcMain.handle('settings:set', (_event, settings) => {
    if (settings.apiKey) store.set('apiKey', settings.apiKey);
    if (settings.model) store.set('model', settings.model);
    if (settings.maxTokens) store.set('maxTokens', settings.maxTokens);
    if (settings.temperature !== undefined) store.set('temperature', settings.temperature);
    logger.info('Settings updated');
    return { success: true };
  });

  // Stats
  ipcMain.handle('stats:get', () => {
    return holySheepService.getStats();
  });
}

// App Lifecycle
app.whenReady().then(() => {
  logger.info('Electron app starting...');
  setupIpcHandlers();
  createWindow();

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

// Global error handlers
process.on('uncaughtException', (error) => {
  logger.error(Uncaught Exception: ${error.message});
});

process.on('unhandledRejection', (reason) => {
  logger.error(Unhandled Rejection: ${reason});
});

Preload Script — Secure Context Bridge

// src/preload/preload.ts
import { contextBridge, ipcRenderer } from 'electron';

export interface AIRequest {
  messages: Array<{ role: string; content: string }>;
  model?: string;
  temperature?: number;
  max_tokens?: number;
}

export interface AIResponse {
  success: boolean;
  data?: {
    content: string;
    usage: {
      prompt_tokens: number;
      completion_tokens: number;
      total_tokens: number;
    };
    latency_ms: number;
  };
  error?: string;
}

const electronAPI = {
  // AI Methods
  ai: {
    chat: (request: AIRequest): Promise<AIResponse> => 
      ipcRenderer.invoke('ai:chat', request),
    chatStream: (request: AIRequest): Promise<AIResponse> =>
      ipcRenderer.invoke('ai:chatStream', request),
    onStreamChunk: (callback: (chunk: string) => void) => {
      const handler = (_event: any, chunk: string) => callback(chunk);
      ipcRenderer.on('ai:streamChunk', handler);
      return () => ipcRenderer.removeListener('ai:streamChunk', handler);
    },
    onStreamError: (callback: (error: string) => void) => {
      const handler = (_event: any, error: string) => callback(error);
      ipcRenderer.on('ai:streamError', handler);
      return () => ipcRenderer.removeListener('ai:streamError', handler);
    }
  },
  // Settings
  settings: {
    get: () => ipcRenderer.invoke('settings:get'),
    set: (settings: any) => ipcRenderer.invoke('settings:set', settings)
  },
  // Stats
  stats: {
    get: () => ipcRenderer.invoke('stats:get')
  }
};

contextBridge.exposeInMainWorld('electronAPI', electronAPI);

// Type declaration for renderer
declare global {
  interface Window {
    electronAPI: typeof electronAPI;
  }
}

React Hook — AI Integration trong Renderer

// src-renderer/hooks/useAI.ts
import { useState, useCallback, useEffect } from 'react';

interface Message {
  id: string;
  role: 'system' | 'user' | 'assistant';
  content: string;
  timestamp: number;
}

interface UseAIOptions {
  systemPrompt?: string;
  model?: string;
  temperature?: number;
  maxTokens?: number;
  stream?: boolean;
}

interface UseAIReturn {
  messages: Message[];
  isLoading: boolean;
  error: string | null;
  sendMessage: (content: string) => Promise;
  clearMessages: () => void;
  stats: { avgLatency: number; totalRequests: number } | null;
}

export function useAI(options: UseAIOptions = {}): UseAIReturn {
  const [messages, setMessages] = useState<Message[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [stats, setStats] = useState<{ avgLatency: number; totalRequests: number } | null>(null);

  // Stream chunk handler
  useEffect(() => {
    if (!options.stream) return;

    const unsubChunk = window.electronAPI.ai.onStreamChunk((chunk) => {
      setMessages((prev) => {
        const lastMsg = prev[prev.length - 1];
        if (lastMsg?.role === 'assistant') {
          return [
            ...prev.slice(0, -1),
            { ...lastMsg, content: lastMsg.content + chunk }
          ];
        }
        return prev;
      });
    });

    const unsubError = window.electronAPI.ai.onStreamError((err) => {
      setError(err);
      setIsLoading(false);
    });

    return () => {
      unsubChunk();
      unsubError();
    };
  }, [options.stream]);

  const sendMessage = useCallback(async (content: string) => {
    setIsLoading(true);
    setError(null);

    // Add user message
    const userMessage: Message = {
      id: user-${Date.now()},
      role: 'user',
      content,
      timestamp: Date.now()
    };

    setMessages((prev) => [...prev, userMessage]);

    // Prepare API request
    const apiMessages = [
      ...(options.systemPrompt
        ? [{ role: 'system' as const, content: options.systemPrompt }]
        : []),
      ...messages.map((m) => ({ role: m.role, content: m.content })),
      { role: 'user' as const, content }
    ];

    try {
      if (options.stream) {
        // Add placeholder assistant message for streaming
        const assistantMessage: Message = {
          id: assistant-${Date.now()},
          role: 'assistant',
          content: '',
          timestamp: Date.now()
        };
        setMessages((prev) => [...prev, assistantMessage]);

        await window.electronAPI.ai.chatStream({
          messages: apiMessages,
          model: options.model,
          temperature: options.temperature,
          max_tokens: options.maxTokens
        });
      } else {
        const response = await window.electronAPI.ai.chat({
          messages: apiMessages,
          model: options.model,
          temperature: options.temperature,
          max_tokens: options.maxTokens
        });

        if (response.success && response.data) {
          const assistantMessage: Message = {
            id: assistant-${Date.now()},
            role: 'assistant',
            content: response.data.content,
            timestamp: Date.now()
          };
          setMessages((prev) => [...prev, assistantMessage]);
        } else {
          setError(response.error || 'Unknown error occurred');
        }
      }

      // Fetch updated stats
      const newStats = await window.electronAPI.stats.get();
      setStats(newStats);
    } catch (err: any) {
      setError(err.message || 'Failed to send message');
    } finally {
      setIsLoading(false);
    }
  }, [messages, options]);

  const clearMessages = useCallback(() => {
    setMessages([]);
    setError(null);
  }, []);

  return {
    messages,
    isLoading,
    error,
    sendMessage,
    clearMessages,
    stats
  };
}

So sánh Chi phí — Trước và Sau khi Di chuyển

ModelGiá Relay (USD/MTok)Giá HolySheep (USD/MTok)Tiết kiệm
GPT-4.1$60.00$8.0086.7%
Claude Sonnet 4.5$100.00$15.0085%
Gemini 2.5 Flash$15.00$2.5083.3%
DeepSeek V3.2$3.00$0.4286%

Với 50,000 người dùng active, mỗi người dùng trung bình 50 request/ngày (2,500 tokens/request):

Kế hoạch Di chuyển — Rollback Strategy

Quy trình di chuyển an toàn với rollback plan:

PHASE 1: PREPARATION (1-2 ngày)
├── Backup current config
├── Store backup in encrypted location
├── Prepare rollback script
└── Test in staging environment

PHASE 2: CANARY DEPLOYMENT (3-5 ngày)
├── Deploy to 5% users
├── Monitor error rates & latency
├── Compare metrics baseline
└── Decision: proceed or rollback

PHASE 3: GRADUAL ROLLOUT (7-14 ngày)
├── 25% → 50% → 100%
├── Daily monitoring
├── Weekly cost analysis
└── User feedback collection

PHASE 4: FULL PRODUCTION
├── Decommission old relay
├── Archive old API keys
└── Update documentation

Rollback script — chạy khi cần quay về:

# rollback-holysheep.sh
#!/bin/bash

echo "Initiating HolySheep rollback..."

Restore old configuration

cp /backup/relay-config.json ./config.json

Restart Electron app

pkill -f "electron" nohup ./electron-app > /var/log/electron-rollback.log 2>&1 &

Verify connection

sleep 5 curl -s https://old-relay-api.example.com/health

Notify team

curl -X POST $SLACK_WEBHOOK \ -H 'Content-type: application/json' \ --data '{"text":"HolySheep rollback completed. Old relay active."}' echo "Rollback complete. Old relay is now active."

ROI Calculator — Tính toán Thực tế

// roi-calculator.html - Chạy trong browser
function calculateROI() {
  const users = parseInt(document.getElementById('users').value) || 50000;
  const requestsPerDay = parseInt(document.getElementById('reqPerDay').value) || 50;
  const avgTokens = parseInt(document.getElementById('avgTokens').value) || 2500;
  const model = document.getElementById('model').value;
  
  const modelPrices = {
    'gpt-4.1': { relay: 60, holy: 8 },
    'claude-sonnet-4.5': { relay: 100, holy: 15 },
    'gemini-2.5-flash': { relay: 15, holy: 2.5 },
    'deepseek-v3.2': { relay: 3, holy: 0.42 }
  };
  
  const prices = modelPrices[model];
  const dailyRequests = users * requestsPerDay;
  const monthlyTokens = (dailyRequests * avgTokens * 30) / 1000000; // in MTokens
  
  const relayCost = monthlyTokens * prices.relay;
  const holyCost = monthlyTokens * prices.holy;
  const savings = relayCost - holyCost;
  const savingsPercent = ((relayCost - holyCost) / relayCost * 100).toFixed(1);
  
  document.getElementById('result').innerHTML = `
    <h3>Kết quả ROI</h3>
    <p>Chi phí Relay/tháng: <strong>$${relayCost.toFixed(2)}</strong></p>
    <p>Chi phí HolySheep/tháng: <strong>$${holyCost.toFixed(2)}</strong></p>
    <p>Tiết kiệm/tháng: <strong>$${savings.toFixed(2)}</strong> (${savingsPercent}%)</p>
    <p>Tiết kiệm/năm: <strong>$${(savings * 12).toFixed(2)}</strong></p>
    <p>Độ trễ trung bình HolySheep: <strong><50ms</strong></p>
  `;
}

Logging và Monitoring

// src/main/utils/logger.ts
import winston from 'winston';
import * as path from 'path';
import { app } from 'electron';

const logDir = app.isPackaged
  ? path.join(app.getPath('userData'), 'logs')
  : path.join(__dirname, '../../logs');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    winston.format.errors({ stack: true }),
    winston.format.printf(({ level, message, timestamp, stack }) => {
      return ${timestamp} [${level.toUpperCase()}]: ${stack || message};
    })
  ),
  transports: [
    new winston.transports.File({
      filename: path.join(logDir, 'error.log'),
      level: 'error',
      maxsize: 5242880, // 5MB
      maxFiles: 5
    }),
    new winston.transports.File({
      filename: path.join(logDir, 'combined.log'),
      maxsize: 5242880,
      maxFiles: 5
    }),
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.simple()
      )
    })
  ]
});

export { logger };

Lỗi thường gặp và cách khắc phục

1. Lỗi "API key chưa được cấu hình"

// Nguyên nhân: store.get('apiKey') trả về chuỗi rỗng
// Hoặc key chưa được set trong electron-store

// Cách khắc phục:
// 1. Kiểm tra file config
const configPath = app.getPath('userData') + '/holysheep-config.json';
console.log('Config path:', configPath);

// 2. Set API key thủ công nếu cần
import Store from 'electron-store';
const store = new Store();
store.set('apiKey', 'YOUR_HOLYSHEEP_API_KEY');
store.set('baseUrl', 'https://api.holysheep.ai/v1');

// 3. Hoặc thông qua Settings UI
// Đảm bảo user nhập key trước khi gọi API
const settings = await window.electronAPI.settings.get();
if (!settings.apiKey) {
  throw new Error('Vui lòng cài đặt HolySheep API key trong Settings');
}

2. Lỗi "ECONNREFUSED" hoặc "Network Error"

// Nguyên nhân: Không thể kết nối api.holysheep.ai
// Có thể do firewall, proxy, hoặc DNS issue

// Cách khắc phục:
// 1. Kiểm tra kết nối
const https = require('https');
https.get('https://api.holysheep.ai/v1/models', (res) => {
  console.log('Status:', res.statusCode);
}).on('error', (err) => {
  console.error('Connection error:', err.message);
});

// 2. Thêm retry logic với exponential backoff
async function retryRequest(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
    }
  }
}

// 3. Fallback sang cached response nếu có
const cachedResponse = cache.get(requestHash);
if (cachedResponse) {
  console.log('Using cached response');
  return cachedResponse;
}

// 4. Kiểm tra proxy settings (nếu cần corporate proxy)
process.env.HTTPS_PROXY = 'http://proxy.company.com:8080';
process.env.HTTP_PROXY = 'http://proxy.company.com:8080';

3. Lỗi "Rate limit exceeded" (429)

// Nguyên nhân: Gửi quá nhiều request trong thời gian ngắn
// HolySheep có limit riêng, cần implement rate limiter

// Cách khắc phục:
// 1. Implement token bucket algorithm
class RateLimiter {
  constructor(maxTokens = 100, refillRate = 10) {
    this.tokens = maxTokens;
    this.maxTokens = maxTokens;
    this.refillRate = refillRate;
    this.lastRefill = Date.now();
  }

  async acquire() {
    this.refill();
    if (this.tokens < 1) {
      const waitTime = (1 - this.tokens) / this.refillRate * 1000;
      await new Promise(r => setTimeout(r, waitTime));
      this.refill();
    }
    this.tokens -= 1;
  }

  refill() {
    const now = Date.now();
    const elapsed = (now - this.lastRefill) / 1000;
    this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate);
    this.lastRefill = now;
  }
}

const limiter = new RateLimiter(60, 10); // 60 requests, refill 10/s

// 2. Queue requests
class RequestQueue {
  constructor(concurrency = 3) {
    this.queue = [];
    this.running = 0;
    this.concurrency = concurrency;
  }

  async add(requestFn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject });
      this.process();
    });
  }

  async process() {
    while (this.running < this.concurrency && this.queue.length > 0) {
      const { requestFn, resolve, reject } = this.queue.shift();
      this.running++;
      
      try {
        const result = await requestFn();
        resolve(result);
      } catch (error) {
        reject(error);
      } finally {
        this.running--;
        this.process();
      }
    }
  }
}

// 3. Sử dụng trong API call
const queue = new RequestQueue(3);

async function thrott