mirror of https://github.com/garrytan/gstack.git
fix(gbrain): stop forcing GBRAIN_PREPARE on transaction-mode poolers (#1965)
buildGbrainEnv auto-set GBRAIN_PREPARE=true whenever DATABASE_URL targeted
port 6543, and the /sync-gbrain capability check exported it for the rest
of the skill run. Both had the semantics inverted: gbrain auto-disables
prepared statements on transaction-mode poolers because they break every
write there ("prepared statement does not exist"); GBRAIN_PREPARE=true is
gbrain's documented override for SESSION-mode poolers on 6543, not a
requirement for transaction mode. The #1435 search symptom the auto-set
worked around was fixed gbrain-side.
Remove both force-sets. A caller-set GBRAIN_PREPARE (either value) still
passes through untouched, preserving the session-mode-on-6543 escape hatch.
isTransactionModePooler stays exported.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a5833c413f
commit
8e4662e930
|
|
@ -58,10 +58,10 @@ export interface BuildGbrainEnvOptions {
|
|||
* Detect whether a DATABASE_URL targets a PgBouncer transaction-mode pooler.
|
||||
*
|
||||
* Supabase transaction-mode poolers conventionally run on port 6543 at
|
||||
* `*.pooler.supabase.com`. When gbrain connects through one of these, it
|
||||
* auto-disables prepared statements — but search requires them (#1435).
|
||||
* Returns `true` when the URL looks like a transaction-mode pooler so the
|
||||
* caller can set `GBRAIN_PREPARE=true` to re-enable prepared statements.
|
||||
* `*.pooler.supabase.com`. gbrain auto-disables prepared statements on these
|
||||
* (prepared statements break under transaction pooling — #1965); its banner
|
||||
* documents `GBRAIN_PREPARE=true` as the override for poolers that actually
|
||||
* run in session mode on 6543.
|
||||
*/
|
||||
export function isTransactionModePooler(url: string): boolean {
|
||||
try {
|
||||
|
|
@ -83,10 +83,11 @@ export function isTransactionModePooler(url: string): boolean {
|
|||
* - the config has no `database_url`,
|
||||
* - the caller already set DATABASE_URL to the same value.
|
||||
*
|
||||
* When the effective DATABASE_URL targets a PgBouncer transaction-mode
|
||||
* pooler (port 6543), sets `GBRAIN_PREPARE=true` so gbrain re-enables
|
||||
* prepared statements needed for search (#1435). Caller can override
|
||||
* with `GBRAIN_PREPARE=false` in the base env.
|
||||
* GBRAIN_PREPARE is never set here (#1965): gbrain auto-disables prepared
|
||||
* statements on transaction-mode poolers itself, and forcing them on breaks
|
||||
* every write with "prepared statement does not exist". A caller-set
|
||||
* GBRAIN_PREPARE (either value) passes through untouched — that remains the
|
||||
* documented override for session-mode poolers on port 6543.
|
||||
*
|
||||
* Always returns a fresh object — mutating the returned env never
|
||||
* affects the caller's env. Tests assert on effective values, not
|
||||
|
|
@ -120,20 +121,6 @@ export function buildGbrainEnv(opts: BuildGbrainEnvOptions = {}): NodeJS.Process
|
|||
}
|
||||
}
|
||||
|
||||
// PgBouncer transaction-mode pooler detection (#1435): when the effective
|
||||
// DATABASE_URL targets port 6543 (Supabase transaction-mode convention),
|
||||
// gbrain auto-disables prepared statements — but search needs them.
|
||||
// Set GBRAIN_PREPARE=true unless the caller explicitly opted out.
|
||||
const effectiveUrl = out.DATABASE_URL || cfg.database_url;
|
||||
if (effectiveUrl && !out.GBRAIN_PREPARE && isTransactionModePooler(effectiveUrl)) {
|
||||
out.GBRAIN_PREPARE = "true";
|
||||
if (opts.announce) {
|
||||
process.stderr.write(
|
||||
`[gbrain-exec] set GBRAIN_PREPARE=true (port 6543 transaction-mode pooler detected)\n`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1013,10 +1013,11 @@ SLUG="_capability_check_$$"
|
|||
CAPABILITY_OK=0
|
||||
if [ -f ~/.gbrain/config.json ] && \
|
||||
gbrain --version 2>/dev/null | grep -q '^gbrain '; then
|
||||
# GBRAIN_PREPARE=true ensures prepared statements stay enabled when
|
||||
# connecting through a PgBouncer transaction-mode pooler (port 6543).
|
||||
# Without it, search silently returns no results (#1435).
|
||||
export GBRAIN_PREPARE=true
|
||||
# Do NOT export GBRAIN_PREPARE here (#1965). gbrain auto-disables prepared
|
||||
# statements on transaction-mode poolers (port 6543) — forcing them on
|
||||
# breaks every write with "prepared statement does not exist". Users on a
|
||||
# session-mode pooler at 6543 can set GBRAIN_PREPARE=true themselves (the
|
||||
# gbrain banner documents this override).
|
||||
if echo "ping" | gbrain put "$SLUG" >/dev/null 2>&1; then
|
||||
# Retry search up to 3 times with 1s delay — under transaction-mode
|
||||
# pooling the search index may not be visible on the next connection
|
||||
|
|
|
|||
|
|
@ -301,10 +301,11 @@ SLUG="_capability_check_$$"
|
|||
CAPABILITY_OK=0
|
||||
if [ -f ~/.gbrain/config.json ] && \
|
||||
gbrain --version 2>/dev/null | grep -q '^gbrain '; then
|
||||
# GBRAIN_PREPARE=true ensures prepared statements stay enabled when
|
||||
# connecting through a PgBouncer transaction-mode pooler (port 6543).
|
||||
# Without it, search silently returns no results (#1435).
|
||||
export GBRAIN_PREPARE=true
|
||||
# Do NOT export GBRAIN_PREPARE here (#1965). gbrain auto-disables prepared
|
||||
# statements on transaction-mode poolers (port 6543) — forcing them on
|
||||
# breaks every write with "prepared statement does not exist". Users on a
|
||||
# session-mode pooler at 6543 can set GBRAIN_PREPARE=true themselves (the
|
||||
# gbrain banner documents this override).
|
||||
if echo "ping" | gbrain put "$SLUG" >/dev/null 2>&1; then
|
||||
# Retry search up to 3 times with 1s delay — under transaction-mode
|
||||
# pooling the search index may not be visible on the next connection
|
||||
|
|
|
|||
|
|
@ -118,15 +118,20 @@ describe("buildGbrainEnv", () => {
|
|||
expect(result.DATABASE_URL).toBe("postgresql://gbrain/db");
|
||||
});
|
||||
|
||||
// --- GBRAIN_PREPARE auto-detection (#1435) ---
|
||||
// --- GBRAIN_PREPARE is never auto-set (#1965) ---
|
||||
// gbrain auto-disables prepared statements on transaction-mode poolers;
|
||||
// forcing GBRAIN_PREPARE=true there breaks every write with "prepared
|
||||
// statement does not exist". The helper must leave the variable alone in
|
||||
// all cases — a caller-set value (the documented session-mode-on-6543
|
||||
// override) passes through untouched.
|
||||
|
||||
it("sets GBRAIN_PREPARE=true when DATABASE_URL targets port 6543 (transaction-mode pooler)", () => {
|
||||
it("does not set GBRAIN_PREPARE when DATABASE_URL targets port 6543 (transaction-mode pooler)", () => {
|
||||
const poolerUrl = "postgresql://postgres.abc:pw@aws-0-us-east-1.pooler.supabase.com:6543/postgres";
|
||||
writeFileSync(join(gbrainHome, "config.json"), JSON.stringify({ database_url: poolerUrl }));
|
||||
const baseEnv = { HOME: home };
|
||||
const result = buildGbrainEnv({ baseEnv });
|
||||
expect(result.DATABASE_URL).toBe(poolerUrl);
|
||||
expect(result.GBRAIN_PREPARE).toBe("true");
|
||||
expect(result.GBRAIN_PREPARE).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not set GBRAIN_PREPARE when DATABASE_URL targets port 5432 (session-mode pooler)", () => {
|
||||
|
|
@ -144,7 +149,7 @@ describe("buildGbrainEnv", () => {
|
|||
expect(result.GBRAIN_PREPARE).toBeUndefined();
|
||||
});
|
||||
|
||||
it("respects caller's explicit GBRAIN_PREPARE=false (opt-out)", () => {
|
||||
it("passes through caller's explicit GBRAIN_PREPARE=false", () => {
|
||||
const poolerUrl = "postgresql://postgres.abc:pw@aws-0-us-east-1.pooler.supabase.com:6543/postgres";
|
||||
writeFileSync(join(gbrainHome, "config.json"), JSON.stringify({ database_url: poolerUrl }));
|
||||
const baseEnv = { HOME: home, GBRAIN_PREPARE: "false" };
|
||||
|
|
@ -152,10 +157,10 @@ describe("buildGbrainEnv", () => {
|
|||
expect(result.GBRAIN_PREPARE).toBe("false");
|
||||
});
|
||||
|
||||
it("sets GBRAIN_PREPARE even when caller DATABASE_URL already matches config on port 6543", () => {
|
||||
it("passes through caller's explicit GBRAIN_PREPARE=true (session-mode-on-6543 override)", () => {
|
||||
const poolerUrl = "postgresql://postgres.abc:pw@aws-0-us-east-1.pooler.supabase.com:6543/postgres";
|
||||
writeFileSync(join(gbrainHome, "config.json"), JSON.stringify({ database_url: poolerUrl }));
|
||||
const baseEnv = { HOME: home, DATABASE_URL: poolerUrl };
|
||||
const baseEnv = { HOME: home, GBRAIN_PREPARE: "true" };
|
||||
const result = buildGbrainEnv({ baseEnv });
|
||||
expect(result.GBRAIN_PREPARE).toBe("true");
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue