Apostolos
Apostolos

Reputation: 8101

Firestore transaction update through cloud function gets "Too much contenation on these documents"

I have the following code:

transaction = client.transaction()

@firestore.transactional
def update_dev_transactional(trans, dev_ref, data):
     snapshot = dev_ref.get(transaction=transaction)
     snapshot_dict = snapshot.to_dict()
     last_seen_at = parser.parse(snapshot_dict.get("last_seen_at"))
     occupied_events = snapshot_dict.get("occupied_events", 0) + 1 if data["objectJSON"]["occupied"] else snapshot_dict.get("occupied")
     stay_duration = snapshot_dict.get("stay_duraion", 0)


     dev_ref.update({
          "last_seen_at": data["rxInfo"][0]["time"],
          "occupied": data["objectJSON"]["occupied"],
          "events_count": snapshot.get("events_count", 0) + 1,
          "occupied_events": occupied_events,
          "stay_duration": stay_duration if data["ojbectJSON"]["occupied"] else stay_duration + (parser.parse(data["rxInfo"][0]["time"]) - last_seen_at).seconds
     })

app_doc_ref = app_sub_col_ref.document(data["applicationID"])
if not app_doc_ref.get().exists:
     app_doc_ref.set({
          "name": data["applicationName"],
          "last_seen_at": data["rxInfo"][0]["time"]
     })
devices_sub_col_ref = app_doc_ref.collection("devices")
device_doc_ref = devices_sub_col_ref.document(data["dev_eui"])
if not device_doc_ref.get().exists:

    document = {
        "devEUI": data["devEUI"],
        "name": data["deviceName"],
        "dev_eui": data["dev_eui"],
        "last_seen_at": data["rxInfo"][0]["time"],
        "occupied": data["objectJSON"]["occupied"],
        "events_count": 1
    }
    device_doc_ref.set(document)
else:
    update_dev_transactional(transaction, device_doc_ref, data)

the code is run inside a Google cloud function that gets triggered by an event in a Pub/Sub topic. data contains the payload of the topic message. The goal is to caclulate the average duration time of a certain state (sensor occupancy). But running this I get the following error

Traceback (most recent call last):
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/functions_framework/__init__.py", line 171, in view_func
    function(data, context)
  File "/workspace/main.py", line 57, in hello_pubsub
    update_dev_transactional(transaction, device_doc_ref, data)
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/cloud/firestore_v1/transaction.py", line 302, in __call__
    result = self._pre_commit(transaction, *args, **kwargs)
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/cloud/firestore_v1/transaction.py", line 245, in _pre_commit
    return self.to_wrap(transaction, *args, **kwargs)
  File "/workspace/main.py", line 16, in update_dev_transactional
    dev_ref.update({
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/cloud/firestore_v1/document.py", line 325, in update
    write_results = batch.commit(**kwargs)
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/cloud/firestore_v1/batch.py", line 59, in commit
    commit_response = self._client._firestore_api.commit(
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/cloud/firestore_v1/services/firestore/client.py", line 815, in commit
    response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,)
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/api_core/gapic_v1/method.py", line 154, in __call__
    return wrapped_func(*args, **kwargs)
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/api_core/retry.py", line 283, in retry_wrapped_func
    return retry_target(
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/api_core/retry.py", line 190, in retry_target
    return target()
  File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/api_core/grpc_helpers.py", line 68, in error_remapped_callable
    raise exceptions.from_grpc_error(exc) from exc
google.api_core.exceptions.Aborted: 409 Too much contention on these documents. Please try again

Why is that? My reads are before my writes. I use the to_dict method to practice some defensive programming since I want also to check "migrating" data (using data that weren't set previously in the document)

Upvotes: 0

Views: 202

Answers (1)

Apostolos
Apostolos

Reputation: 8101

Found the error!! I needed to call

trans.update(dev_ref, {...})

instead of

dev_ref.update({...})

Everything works great now!

Upvotes: 1

Related Questions