testing 127.0.0.1 issue

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-07-07 13:39:46 +08:00
parent 095a0d4b3c
commit 062f3b7cfa
11 changed files with 262 additions and 123 deletions
+13 -56
View File
@@ -46,64 +46,21 @@ const DEFAULT_BUCKET = process.env.S3_BUCKET;
// from the machine running Garage itself; S3_PUBLIC_URL is the externally
// reachable address (tunnel/CDN/domain).
//
// Rather than always preferring one, probe S3_ENDPOINT and use it when it's
// actually reachable (same-machine dev setup — no extra hop through the
// tunnel), falling back to S3_PUBLIC_URL when it isn't (any other machine).
//
// The probe runs once at startup and then on a background timer — never on
// the request path itself. A machine without Garage would otherwise pay the
// full HeadBucket timeout on whichever upload/asset request happens to land
// right after the cache expires; polling in the background means every
// request just reads the last known-good host instantly.
const PROBE_TIMEOUT_MS = 1500;
const PROBE_CACHE_MS = 15000;
let hostCache = { host: process.env.S3_PUBLIC_URL || process.env.S3_ENDPOINT || "" };
async function probeEndpoint(endpoint) {
const probe = new S3Client({
endpoint,
region: process.env.S3_REGION || "garage",
credentials,
forcePathStyle: true,
});
await Promise.race([
probe.send(new HeadBucketCommand({ Bucket: DEFAULT_BUCKET })),
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), PROBE_TIMEOUT_MS)),
]);
// This used to probe S3_ENDPOINT from the server and prefer it when reachable,
// but that measures the wrong machine: Garage is always co-located with this
// backend (see docker-compose.yml), so the probe was *always* reachable from
// here and always resolved to 127.0.0.1 — even for browsers on other machines,
// which then failed to connect to it. There is no way for the server to
// determine what's reachable from the client by probing itself, so just trust
// config: prefer S3_PUBLIC_URL whenever it's set, and only fall back to
// S3_ENDPOINT for pure single-machine dev setups with no public URL at all.
function resolvePublicHost() {
return process.env.S3_PUBLIC_URL || process.env.S3_ENDPOINT || "";
}
async function refreshHostCache() {
const endpoint = process.env.S3_ENDPOINT;
const publicUrl = process.env.S3_PUBLIC_URL || "";
if (!endpoint) { hostCache = { host: publicUrl }; return; }
if (!publicUrl) { hostCache = { host: endpoint }; return; }
try {
await probeEndpoint(endpoint);
hostCache = { host: endpoint };
} catch {
hostCache = { host: publicUrl };
}
}
// Kick off the first probe immediately so the cache is populated before any
// request needs it, then keep it fresh in the background. unref() so this
// timer alone doesn't keep the process (or a test run) alive.
const initialProbe = refreshHostCache();
const refreshTimer = setInterval(refreshHostCache, PROBE_CACHE_MS);
refreshTimer.unref?.();
async function resolvePublicHost() {
await initialProbe; // no-op after the first call — already resolved
return hostCache.host;
}
// Public client — lazily built against whichever host resolvePublicHost()
// picks, so it follows the reachability check instead of a fixed endpoint.
async function getPublicClient() {
const endpoint = await resolvePublicHost();
// Public client — built against whichever host resolvePublicHost() picks.
function getPublicClient() {
const endpoint = resolvePublicHost();
return new S3Client({
endpoint,
region: process.env.S3_REGION || "garage",