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

Firestore Emulator Cloud Trigger Issue with Write Operations #174

Open
DominicOrga opened this issue Feb 11, 2024 · 1 comment · Fixed by googleapis/python-firestore#843
Labels
bug Something isn't working emulator

Comments

@DominicOrga
Copy link

DominicOrga commented Feb 11, 2024

Invoking an update or set operation to write to a Firestore document via the Firestore client does not work when called in a Firestore Emulator Cloud Trigger. Everything works fine when the function is deployed on the cloud.

In the following code example, whenever a document in collection_A gets updated, an event trigger does the ff:

  • field_1a is set to true by using the event's document reference (WORKS)
  • field_2a is set to true by using the Firestore client (DOES NOT WORK)
  • Create a new document using the Firestore client (DOES NOT WORK)
from firebase_admin import firestore
from firebase_functions.firestore_fn import (Change, DocumentSnapshot, Event,
                                             on_document_updated)
from google.cloud.firestore import Client


@on_document_updated(document='collection_A/{document_id}')
def on_document_A_updated(event: Event[Change[DocumentSnapshot]]):
    new_doc = event.data.after
    data = new_doc.to_dict()

    if not data.get('field_1a'):
        # WORKS
        #
        # Using the document reference from the event works fine to update the
        # document.

        new_doc.reference.update({'field_1a': True})

    firestore_client: Client = firestore.Client()

    if not data.get('field_2a'):
        # DOES NOT WORK
        #
        # Using a document reference fetched from the client does not work
        # to update the document.

        firestore_client\
            .document(new_doc.reference.path)\
            .update({'field_2a': True})

    # DOES NOT WORK
    #
    # Creating a new document does not work.

    firestore_client\
        .collection('collection_B')\
        .document()\
        .set({'field_1b': 1})
@exaby73
Copy link
Contributor

exaby73 commented Feb 12, 2024

I can reproduce this issue. I believe this issue exists in the google python library, rather than this SDK. I will raise it with the team and discuss this further there. Thanks for catching this

Python example used is same as above. For testing Node, I used the following code:

import * as admin from "firebase-admin";
import { getFirestore } from "firebase-admin/firestore";
import { onDocumentUpdated } from "firebase-functions/v2/firestore";
import { setGlobalOptions } from "firebase-functions/v2/options";

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
});

export const helloWorld = onDocumentUpdated(
  "collection_A/{document_id}",
  (event) => {
    const newDoc = event.data!.after;
    const data = newDoc.data();

    if (!data["field_1a"]) {
      newDoc.ref.update({ field_1a: true });
    }

    const firesore = getFirestore();

    if (!data["field_2a"]) {
      firesore.doc(newDoc.ref.path).update({ field_2a: true });
    }

    firesore.collection("collection_B").doc().set({ field_1b: 1 });
  }
);
Logs
>  [2024-02-12 10:57:03,192] ERROR in app: Exception on /functions/projects/ [POST]
>  Traceback (most recent call last):
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/api_core/grpc_helpers.py", line 75, in error_remapped_callable
>      return callable_(*args, **kwargs)
>             ^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/grpc/_channel.py", line 1161, in __call__
>      return _end_unary_response_blocking(state, call, False, None)
>             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/grpc/_channel.py", line 1004, in _end_unary_response_blocking
>      raise _InactiveRpcError(state)  # pytype: disable=not-instantiable
>      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
>       status = StatusCode.NOT_FOUND
>       details = "no entity to update: app: "dev~google-cloud-firestore-emulator"
>  path <
>    Element {
>      type: "collection_A"
>      name: "fQar1nTG4HShEHkad0Zp"
>    }
>  >
>  "
>       debug_error_string = "UNKNOWN:Error received from peer  {grpc_message:"no entity to update: app: \"dev~google-cloud-firestore-emulator\"\npath <\n  Element {\n    type: \"collection_A\"\n    name: \"fQar1nTG4HShEHkad0Zp\"\n  }\n>\n", grpc_status:5, created_time:"2024-02-12T10:57:03.192387+00:00"}"
>  >
>  
>  The above exception was the direct cause of the following exception:
>  
>  Traceback (most recent call last):
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/flask/app.py", line 2190, in wsgi_app
>      response = self.full_dispatch_request()
>                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/flask/app.py", line 1486, in full_dispatch_request
>      rv = self.handle_user_exception(e)
>           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/flask/app.py", line 1484, in full_dispatch_request
>      rv = self.dispatch_request()
>           ^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/flask/app.py", line 1469, in dispatch_request
>      return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
>             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/functions_framework/__init__.py", line 174, in view_func
>      function(event)
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/firebase_functions/firestore_fn.py", line 255, in on_document_updated_wrapped
>      return _firestore_endpoint_handler(
>             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/firebase_functions/firestore_fn.py", line 176, in _firestore_endpoint_handler
>      func(database_event)
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/main.py", line 30, in on_document_A_updated
>      .update({'field_2a': True})
>       ^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/cloud/firestore_v1/document.py", line 325, in update
>      write_results = batch.commit(**kwargs)
>                      ^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/cloud/firestore_v1/batch.py", line 59, in commit
>      commit_response = self._client._firestore_api.commit(
>                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/cloud/firestore_v1/services/firestore/client.py", line 1125, in commit
>      response = rpc(
>                 ^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/api_core/gapic_v1/method.py", line 131, in __call__
>      return wrapped_func(*args, **kwargs)
>             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/api_core/retry.py", line 366, in retry_wrapped_func
>      return retry_target(
>             ^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/api_core/retry.py", line 204, in retry_target
>      return target()
>             ^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/api_core/timeout.py", line 120, in func_with_timeout
>      return func(*args, **kwargs)
>             ^^^^^^^^^^^^^^^^^^^^^
>    File "/Users/nabeelparkar/dev/testing/python-functions/functions/venv/lib/python3.11/site-packages/google/api_core/grpc_helpers.py", line 77, in error_remapped_callable
>      raise exceptions.from_grpc_error(exc) from exc
>  google.api_core.exceptions.NotFound: 404 no entity to update: app: "dev~google-cloud-firestore-emulator"
>  path <
>    Element {
>      type: "collection_A"
>      name: "fQar1nTG4HShEHkad0Zp"
>    }
>  >
>  

@exaby73 exaby73 added bug Something isn't working emulator labels Feb 12, 2024
daniel-sanche added a commit to googleapis/python-firestore that referenced this issue Feb 16, 2024
Previously, if `FIRESTORE_EMULATOR_HOST` was set and a `Client` instance was created without an explicit project, it would fall-back to `google-cloud-firestore-emulator`

This change makes it check the `GCLOUD_PROJECT` variable for a project id first, which is used by the firebase functions emulator. This means the client will auto-detect the project id if not given in the emulator, just like in a live GCP environment

Fixes firebase/firebase-functions-python#174
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working emulator
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants