[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DocumentReference.create() keeps trying to create an already existing document, leading to a hang in functions #2587

Open
jellynoone opened this issue Jun 4, 2024 · 12 comments
Assignees

Comments

@jellynoone
Copy link

[READ] Step 1: Are you in the right place? ✅

[REQUIRED] Step 2: Describe your environment

  • Operating System version: MacOS 14.5
  • Firebase Product: functions, firestore
  • Node.js version: v18.20.3
  • NPM version: 10.7.0

[REQUIRED] Step 3: Describe the problem

Steps to reproduce:

  1. Create a new demo project via firebase init
  2. Select functions and firestore
  3. Run emulators through: firebase emulators:start --inspect-functions --project demo-me
  4. Visit http://127.0.0.1:5001/demo-me/us-central1/runMeTwice in browser
  5. Refresh

Relevant Code:

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "engines": {
    "node": "18"
  },
  "main": "index.js",
  "dependencies": {
    "firebase-admin": "^12.1.0",
    "firebase-functions": "^5.0.0"
  },
  "private": true
}
//@ts-check
const { onRequest } = require("firebase-functions/v2/https");
const logger = require("firebase-functions/logger");
const { firestore, initializeApp } = require("firebase-admin");
const { initializeFirestore } = require("firebase-admin/firestore");

/** @type {firestore.Firestore} */
let _defaultFirestore;
function defaultFirestore() {
    return _defaultFirestore ??= initializeFirestore(initializeApp(), {
        preferRest: true,
    })
}

exports.runMeTwice = onRequest(async (_, res) => {
    try {
        const doc = defaultFirestore().collection("test").doc("smt");
        await doc.create({});
        logger.log("Created");
    } catch (error) {
        logger.log(error);
    } finally {
        res.end();
    }
});

Expected behavior

The second time the function is ran, it should fail.

Actual behavior

The first time the function is run the document is created. The second time, the function never completes.

Additionally, attaching to the node process, it seems the creation process keeps getting retried even though it should fail.

@google-oss-bot
Copy link

I found a few problems with this issue:

  • I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
  • This issue does not seem to follow the issue template. Make sure you provide all the required information.

@jellynoone
Copy link
Author

In addition, performing this in a transaction will eventually fail and terminate the function.
However, attaching the debugger it shows, the transaction is still attempted multiple times.
This seems incorrect.

exports.runMeTwice = onRequest(async (_, res) => {
    try {
        const firestore = defaultFirestore();
        await firestore.runTransaction(async (txn) => {
            txn.create(firestore.collection("test").doc("smt"), {});
        })
        logger.log("Created");
    } catch (error) {
        logger.log(error);
    } finally {
        res.end();
    }
});

@cherylEnkidu
Copy link

Hi @jellynoone ,

I will take a look at this and get back to you.

@cherylEnkidu
Copy link

@jellynoone

While investigating, there are some things can be tried as a workaround:

@cherylEnkidu
Copy link
cherylEnkidu commented Jun 5, 2024

This is the code I used to reproduce the issue against production, it throws Document already exists successfully.

const ref = randomCol.doc();
await ref.create({});
const snap1 = await ref.get();

await ref.create({});

Are you testing against production or emulator?

@jellynoone
Copy link
Author
jellynoone commented Jun 6, 2024

I'm testing this against the emulator. Did you try with the provided example?
I think the preferRest: true, configuration option might be significant.

Tested this again against the emulator, without preferRest the function completes with an error. With preferRest the function hangs.

@jellynoone
Copy link
Author

@cherylEnkidu Did you perhaps have a chance to reevaluate based on the additional information provided?

@cherylEnkidu
Copy link

Hi @jellynoone ,

I will continue the investigation this week, and I will reply the ticket as soon as I get any updates :)

@jellynoone
Copy link
Author

Hi @cherylEnkidu were you able to take a look?

@cherylEnkidu
Copy link

Hi @jellynoone ,

Thanks for the waiting. I tried the same code you provided, but the process never hangs. Could you please provided a small repo app?

@jellynoone
Copy link
Author

Attaching a small repro app.

export.zip

Additional notes:

  • The problem reproduces in:
    • emulated environments
    • against the live Firestore instance being called locally
  • The function has to be called two times
    • The first call will complete normally
    • The second call will hang

@jellynoone
Copy link
Author

@cherylEnkidu Attaching a video of the bug being reproduced.

Bug.mp4

In the video I'm using firebase emulators:start --project demo-me to start the emulators without needing a real project. However, I tested this with a live Firestore instance and emulated functions and observed the same bug.

In addition, in the video I'm calling curl instead of the browser to make the process more streamlined.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants