firebase / firebase/firebase-functions-python

`firestore_fn` builds a new `firestore_v1.Client` (and calls `google.auth.default()`) on every event delivery

Abierto
#309 2 comentarios 0 reacciones 0 asignados Ver en GitHub
bug reproduced
Lenguaje dominante
Python
Estrellas
167
Forks
34
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

**Version:** firebase-functions 0.5.0 (same code on `main` / 0.6.0), Python 3.14, Cloud Run functions gen2, google-auth 2.53.0

**What happens**

`firebase_functions/firestore_fn.py::_firestore_endpoint_handler` does, per delivery:

```python
if _DEFAULT_APP_NAME not in _apps:
initialize_app()
app = get_app()
firestore_client = _firestore_v1.Client(project=app.project_id, database=event_database)
```

`google.cloud.firestore_v1.Client(...)` with no `credentials=` calls `google.auth.default()`,
which on Cloud Run pings the metadata server (`google.auth.compute_engine._metadata.ping`).
That ping only retries on `TransportError`; any non-`200 + Metadata-Flavor: Google` answer
returns `False` immediately, and gen2's sandbox has no DMI fallback, so the call raises
`DefaultCredentialsError` — before the user's handler runs and before any user-level error
handling can see it.

We observed this on a **warm** instance that had been serving for three hours and had served
nine events in the previous thirty seconds: four concurrent deliveries at
`2026-08-28T21:40:13Z` all died in the framework with

```
File "firebase_functions/firestore_fn.py", line 145, in _firestore_endpoint_handler
firestore_client = _firestore_v1.Client(project=app.project_id, database=event_database)
...
File "google/auth/_default.py", line 748, in default
raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)
```

while `firebase_admin` in the same process already held perfectly good cached credentials.
Thirty seconds later the same instance logged a TLS EOF talking to an unrelated host, so the
trigger was a brief network hiccup on that instance — but the per-event credential lookup is
what turned it into four dropped events (the trigger had no retry policy).

**Why it matters**

- The client is only used to decode the snapshot (`_firestore_helpers.decode_dict(...,
firestore_client)` and `DocumentReference`); it never talks to Firestore for that. A
credential lookup per event is pure overhead and a per-event failure point.
- The failure happens before user code, so `retry` on the trigger is the only mitigation
available to users.

**Suggested fix**

Reuse the admin app's client (`firebase_admin.firestore.client(app, database_id=...)`) or
cache one `firestore_v1.Client` per `(project, database)` at module level, so
`google.auth.default()` runs once per process instead of once per event. Passing
`credentials=app.credential.get_credential()` into the `Client` constructor would also avoid
the per-event lookup.

**Related gap (worth a second issue or the same one)**

`FirestoreOptions._endpoint` hardcodes `retry=False` and `FirestoreOptions` does not accept a
`retry` keyword (`TypeError: FirestoreOptions.__init__() got an unexpected keyword argument
'retry'`), even though `EventHandlerOptions.retry` exists and the Node SDK exposes `retry` on
Firestore triggers. The only way to get an Eventarc retry policy from Python today is to
mutate `fn.__firebase_endpoint__.eventTrigger["retry"]` after decoration.

**Repro**

Any Firestore trigger; make the metadata server return a non-200 for one request (or block
`169.254.169.254` briefly) on a warm instance and deliver an event. The handler never runs.

Guía de contribución

Abrir la guía de contribución

Línea de trabajo

Start in firebase_functions/firestore_fn.py::_firestore_endpoint_handler and trace how firestore_client is passed to firestore_helpers.decode_dict. Compare the suggested admin-app client, per-database cache, and explicit credentials approaches, then verify that snapshot decoding still works without a credential lookup on every delivery. Review FirestoreOptions._endpoint separately if the retry-policy gap is included.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
google-cloud, python
Área
backend, databases
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Activo
Claridad
Bastante claro
Aptitud para principiantes
48/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.