From f961ab35022b56387cabdb0d47591e07cd065b82 Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Sat, 2 May 2026 11:29:36 -0700 Subject: [PATCH] fix(api): use global undici dispatcher for HTTP_PROXY across all data providers Switch to setGlobalDispatcher(new EnvHttpProxyAgent()) at bootstrap so every service that uses native fetch picks up HTTP_PROXY / HTTPS_PROXY / NO_PROXY without per-call wiring. Reverts the inline ProxyAgent in manual.service.ts because the global dispatcher covers it (and the other 7 services that hit native fetch: coingecko, openfigi, trackinsight, eod-historical-data, financial-modeling-prep, ghostfolio, rapid-api). Also gets NO_PROXY handling for free, which the inline ProxyAgent path did not have. Matches the approach @dtslvr suggested in #6206. --- apps/api/src/main.ts | 6 ++++++ .../data-provider/manual/manual.service.ts | 17 ++--------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index f08a09a83..1e4aaa4e3 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -18,10 +18,16 @@ import type { NestExpressApplication } from '@nestjs/platform-express'; import cookieParser from 'cookie-parser'; import { NextFunction, Request, Response } from 'express'; import helmet from 'helmet'; +import { EnvHttpProxyAgent, setGlobalDispatcher } from 'undici'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; +// Route Node's global `fetch` (used by all data-provider services) through +// HTTP_PROXY / HTTPS_PROXY when those env vars are set. Native fetch +// otherwise ignores them. EnvHttpProxyAgent reads NO_PROXY natively. +setGlobalDispatcher(new EnvHttpProxyAgent()); + async function bootstrap() { const configApp = await NestFactory.create(AppModule); const configService = configApp.get(ConfigService); diff --git a/apps/api/src/services/data-provider/manual/manual.service.ts b/apps/api/src/services/data-provider/manual/manual.service.ts index 6e825d950..51e65e631 100644 --- a/apps/api/src/services/data-provider/manual/manual.service.ts +++ b/apps/api/src/services/data-provider/manual/manual.service.ts @@ -27,7 +27,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import * as cheerio from 'cheerio'; import { addDays, format, isBefore } from 'date-fns'; -import { ProxyAgent } from 'undici'; @Injectable() export class ManualService implements DataProviderInterface { @@ -293,24 +292,12 @@ export class ManualService implements DataProviderInterface { }): Promise { let locale = scraperConfiguration.locale; - const fetchOptions: RequestInit & { dispatcher?: ProxyAgent } = { + const response = await fetch(scraperConfiguration.url, { headers: scraperConfiguration.headers as HeadersInit, signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') ) - }; - - const proxyUrl = - process.env.HTTPS_PROXY ?? - process.env.https_proxy ?? - process.env.HTTP_PROXY ?? - process.env.http_proxy; - - if (proxyUrl) { - fetchOptions.dispatcher = new ProxyAgent(proxyUrl); - } - - const response = await fetch(scraperConfiguration.url, fetchOptions); + }); if (!response.ok) { throw new Error(