test_hang.cjs 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. // Mock @langchain/openai 让 fetch hang(永不响应)测真实路径 invokeWithRetry
  2. process.on('SIGTERM', () => process.exit(0));
  3. const Module = require('module');
  4. const origResolve = Module._resolve_filename = Module._resolveFilename;
  5. let hookInstalled = false;
  6. function installFetchHang(MockClass) {
  7. const origInvoke = MockClass.prototype.invoke;
  8. let invokeCount = 0;
  9. let nodeIndex = 0;
  10. MockClass.prototype.invoke = async function patchedInvoke(messages) {
  11. invokeCount++;
  12. console.log(`[hang-mock] invoke #${invokeCount} on instance with model=${this.model} apiKey-end=${(this.apiKey || '').slice(-12)}`);
  13. // 模拟 HTTP 永不响应 — 返回一个永远不 resolve 的 Promise
  14. // 但调用 await Promise.race / onTimeout 让超时能 abort
  15. return new Promise((_, reject) => {
  16. // 100ms 后抛"timeout"模拟 disconnect-after-start
  17. setTimeout(() => {
  18. const err = new Error('Request timed out after 30000ms (fake hang)');
  19. err.name = 'AbortError';
  20. reject(err);
  21. }, 30000);
  22. });
  23. };
  24. return MockClass;
  25. }
  26. const origLoad = Module._load;
  27. Module._load = function (req, parent, ...rest) {
  28. const exported = origLoad.call(this, req, parent, ...rest);
  29. if (req === '@langchain/openai' && !hookInstalled) {
  30. hookInstalled = true;
  31. if (exported.ChatOpenAI) {
  32. return { ...exported, ChatOpenAI: installFetchHang(exported.ChatOpenAI) };
  33. }
  34. }
  35. return exported;
  36. };
  37. // 真实入口
  38. const llm = require('/data/ai/audio/server/dist/services/llm');
  39. (async () => {
  40. const start = Date.now();
  41. console.log('[t=0] calling callLLMWithMessages (qwen3.5-flash) — should fallback through providers');
  42. try {
  43. const r = await llm.callLLMWithMessages(
  44. [
  45. { role: 'user', content: '一句话总结' }
  46. ],
  47. 'qwen3.5-flash',
  48. 100
  49. );
  50. console.log(`[t=${(Date.now() - start) / 1000}s] OK: ${r.slice(0, 100)}`);
  51. } catch (e) {
  52. console.log(`[t=${(Date.now() - start) / 1000}s] ERR name=${e?.name}: ${e?.message?.slice(0, 200)}`);
  53. if (e.attempts) {
  54. console.log('attempts:', JSON.stringify(e.attempts, null, 2));
  55. }
  56. }
  57. process.exit(0);
  58. })();