firebase-functions-python
firebase-functions-python copied to clipboard
Firestore Emulator Cloud Trigger Issue with Write Operations
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_1ais set totrueby using the event's document reference (WORKS)field_2ais set totrueby 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})
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"
> }
> >
>