firebase-functions-python icon indicating copy to clipboard operation
firebase-functions-python copied to clipboard

Firestore Emulator Cloud Trigger Issue with Write Operations

Open DominicOrga opened this issue 1 year ago • 1 comments

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})

DominicOrga avatar Feb 11 '24 09:02 DominicOrga

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 avatar Feb 12 '24 11:02 exaby73