Skip to content
This repository has been archived by the owner on Apr 3, 2024. It is now read-only.

Commit

Permalink
fix: add timeout to firebase db connection attempt (#1132)
Browse files Browse the repository at this point in the history
Firebase database reads/writes can hang indefinitely if there is an issue with the credentials or with the database url.

Fixing https://togithub.com/firebase/firebase-admin-node/issues/2004 will address this issue, but until then this PR adds a timeout to ensure that errors are emitted.
  • Loading branch information
mctavish committed Jan 16, 2023
1 parent afe9f53 commit 8cd89c8
Showing 1 changed file with 58 additions and 37 deletions.
95 changes: 58 additions & 37 deletions src/agent/firebase-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ const debuglog = util.debuglog('cdbg.firebase');

const FIREBASE_APP_NAME = 'cdbg';

/**
* Waits ms milliseconds for the promise to resolve, or rejects with a timeout.
* @param ms
* @param promise
* @returns Promise wrapped in a timeout.
*/
const withTimeout = (ms: number, promise: Promise<any>) => {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(`Timed out after ${ms} ms.`), ms)
);
return Promise.race([promise, timeout]);
};

export class FirebaseController implements Controller {
db: firebase.database.Database;
debuggeeId?: string;
Expand Down Expand Up @@ -75,54 +88,62 @@ export class FirebaseController implements Controller {
}

// Build the database URL.
let databaseUrl: string;
const databaseUrls = [];
if (options.databaseUrl) {
databaseUrl = options.databaseUrl;
databaseUrls.push(options.databaseUrl);
} else {
// TODO: Add fallback to -default
databaseUrl = `https://${projectId}-cdbg.firebaseio.com`;
databaseUrls.push(`https://${projectId}-cdbg.firebaseio.com`);
databaseUrls.push(`https://${projectId}-default-rtdb.firebaseio.com`);
}

let app: firebase.app.App;
if (credential) {
app = firebase.initializeApp(
{
credential: credential,
databaseURL: databaseUrl,
},
FIREBASE_APP_NAME
);
} else {
// Use the default credentials.
app = firebase.initializeApp(
{
databaseURL: databaseUrl,
},
FIREBASE_APP_NAME
);
}
for (const databaseUrl of databaseUrls) {
let app: firebase.app.App;
if (credential) {
app = firebase.initializeApp(
{
credential: credential,
databaseURL: databaseUrl,
},
FIREBASE_APP_NAME
);
} else {
// Use the default credentials.
app = firebase.initializeApp(
{
databaseURL: databaseUrl,
},
FIREBASE_APP_NAME
);
}

const db = firebase.database(app);
const db = firebase.database(app);

// Test the connection by reading the schema version.
try {
const version_snapshot = await db.ref('cdbg/schema_version').get();
if (version_snapshot) {
const version = version_snapshot.val();
debuglog(
`Firebase app initialized. Connected to ${databaseUrl}` +
` with schema version ${version}`
// Test the connection by reading the schema version.
try {
const version_snapshot = await withTimeout(
10000,
db.ref('cdbg/schema_version').get()
);
} else {
if (version_snapshot) {
const version = version_snapshot.val();
debuglog(
`Firebase app initialized. Connected to ${databaseUrl}` +
` with schema version ${version}`
);

return db;
} else {
throw new Error('failed to fetch schema version from database');
}
} catch (e) {
debuglog(`failed to connect to database ${databaseUrl}: ` + e);
app.delete();
throw new Error('failed to fetch schema version from database');
}
} catch (e) {
app.delete();
throw e;
}

return db;
throw new Error(
`Failed to initialize FirebaseApp, attempted URLs: ${databaseUrls}`
);
}

/**
Expand Down

0 comments on commit 8cd89c8

Please sign in to comment.