Harden Tahesab HTTP client against keep-alive hangs and retry health on alt ports.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-03 17:02:14 +03:30
co-authored by Cursor
parent 17628722d3
commit beae16437b
3 changed files with 164 additions and 52 deletions
@@ -1,5 +1,9 @@
import { randomBytes } from 'crypto';
import type { TahesabHttpClient, TahesabCallOptions } from './tahesab-http.client';
import {
tahesabHealthBaseCandidates,
type TahesabHttpClient,
type TahesabCallOptions,
} from './tahesab-http.client';
export type ConnCreds = {
baseUrl: string;
@@ -178,46 +182,67 @@ export class TahesabApi {
}
/**
* تست سلامت مطابق Postman ته‌حساب:
* ابتدا ریشهٔ baseUrl، بعد /CheckHealth، در نهایت مسیر SSL یا No-SSL بر اساس پروتکل.
* تست سلامت مطابق Postman ته‌حساب (ریشه + CheckHealth).
* روی تایم‌اوت، پورت/پروتکل جایگزین (8081/9550) و در صورت نیاز TLS بدون verify را هم امتحان می‌کند.
*/
async checkHealth() {
const isHttps = /^https:/i.test(this.creds.baseUrl.trim());
const timeoutMs = 12_000;
async checkHealth(): Promise<{
Status?: string;
Api_Status?: string;
usedBaseUrl?: string;
usedPath?: string;
usedInsecureTls?: boolean;
}> {
const timeoutMs = 8_000;
type Health = { Status?: string; Api_Status?: string };
const attempts: Array<{
path: string;
bodyKey?: string;
method: 'GET' | 'POST';
}> = [
{ path: '', method: 'GET' },
{ path: '', bodyKey: 'CheckHealth', method: 'POST' },
{ path: 'CheckHealth', method: 'GET' },
{
path: isHttps ? 'CheckHealth-SSL' : 'CheckHealth-No-SSL',
method: 'GET',
},
];
const bases = tahesabHealthBaseCandidates(this.creds.baseUrl);
const insecureFlags = this.creds.allowInsecureTls
? [true]
: [false, true];
let lastErr: unknown;
for (const attempt of attempts) {
try {
return await this.call<Health>(
attempt.path,
attempt.bodyKey,
attempt.bodyKey ? [] : undefined,
attempt.method,
timeoutMs,
);
} catch (err) {
lastErr = err;
const msg = err instanceof Error ? err.message : String(err);
// خطای گواهی با تلاش‌های بعدی روی همان https حل نمی‌شود
if (/certificate|UNABLE_TO_VERIFY|self-signed|CERT_/i.test(msg)) {
throw err;
for (const baseUrl of bases) {
const isHttps = /^https:/i.test(baseUrl);
const pathAttempts: Array<{
path: string;
bodyKey?: string;
method: 'GET' | 'POST';
}> = [
{ path: '', method: 'GET' },
{ path: '', bodyKey: 'CheckHealth', method: 'POST' },
{ path: 'CheckHealth', method: 'GET' },
{
path: isHttps ? 'CheckHealth-SSL' : 'CheckHealth-No-SSL',
method: 'GET',
},
];
for (const allowInsecureTls of insecureFlags) {
if (!isHttps && allowInsecureTls) continue;
for (const attempt of pathAttempts) {
try {
const health = await this.http.call<Health>({
...this.creds,
baseUrl,
allowInsecureTls,
path: attempt.path,
bodyKey: attempt.bodyKey,
args: attempt.bodyKey ? [] : undefined,
method: attempt.method,
timeoutMs,
});
return {
...health,
usedBaseUrl: baseUrl,
usedPath: attempt.path || '(root)',
usedInsecureTls: allowInsecureTls,
};
} catch (err) {
lastErr = err;
}
}
}
}
throw lastErr instanceof Error
? lastErr
: new Error('تست اتصال ته‌حساب ناموفق بود.');