firebase / firebase/firebase-js-sdk
GRPC errors intermittently cause firebase client to fail
- Dominant language
- TypeScript
- Stars
- 5.1k
- Forks
- 1k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 37
Description
### [REQUIRED] Describe your environment
* Operating System version: MAC OS Montery 12.4
* Browser version: Node 16.16.0
* Firebase SDK version: 9.12.1
* Firebase Product: Firestore
### [REQUIRED] Describe the problem
Our application is experiencing problems with firebase `getDocs()` never responding, and random `grpc connection error` messages when writing documents.
At my workplace we were experiencing several issues.
Our application has a lot of reads and writes going on, so i created a test script to simulate this environment without any of our proprietary code; and i was able to semi-reliably replicate the exact error codes we are experiencing.
#### Steps to reproduce:
* Create a test.js file with the following code
* Update the config with your own values
* Start your own firebase emulator suite
* run `node test.js`
* This will iteratively create a bunch of users and read a bunch of users, basically doing a stress test.
* This SHOULD throw a bunch of GRPC errors, and then throw a custom error of `get timeout - read took over 5 seconds`
* Run the test a few times, rarely it will happily work, but most times it repeatably throws the errors
#### Relevant Code:
```javascript
const { initializeApp } = require("firebase/app");
const { getFirestore, collection, getDocs, addDoc, doc, deleteDoc, connectFirestoreEmulator } = require('firebase/firestore');
const config = {
"firestoreEmulatorPort": 9098,
"firebase": {
"apiKey": "<>",
"projectId": "<>",
"appId": "<>",
}
}
const app = initializeApp(config.firebase);
const db = getFirestore(app);
connectFirestoreEmulator(db, 'localhost', config.firestoreEmulatorPort);
function timeoutReject (timeMs, message) {
return new Promise((resolve, reject) => setTimeout(() => reject(new Error(message)), timeMs));
}
async function run (batchIndex, runIndex) {
// Add user to db
console.time(`write ${batchIndex}-${runIndex}`)
const writeDocs = addDoc(collection(db, "users"), {
first: "Ada",
last: "Lovelace",
born: 1815
});
writeDocs.catch(error => { console.error('error writing user', error, batchIndex)})
const user = await writeDocs
console.timeEnd(`write ${batchIndex}-${runIndex}`)
// Get all users
console.time(`read ${batchIndex}-${runIndex}`)
const query = getDocs(collection(db, "users"));
query.catch(error => { console.error('error resolving promise', error, batchIndex); });
const allUsers = await Promise.race([
query,
timeoutReject(5000, `Get Timeout - Reading took over 5 seconds ${batchIndex}`)
])
console.log(`read success - ${allUsers.size}`)
console.timeEnd(`read ${batchIndex}-${runIndex}`)
}
// Run stress test
async function runTest() {
// Run twenty batches
for (let batchIndex = 0; batchIndex < 20; batchIndex++) {
// In each batch, do 50 "test runs"
const runs = new Array(50).fill(null).map( (value, runIndex) => {
return run(batchIndex, runIndex)
})
await Promise.all(runs)
}
console.log('stress test complete')
process.exit()
}
runTest();
```
#### Example Errors




Contributor guide
Assessment
This issue has not been assessed yet.