Skip to content

Transaction lock timeout error #8105

@onurdialpad

Description

@onurdialpad

[REQUIRED] Environment info

firebase-tools: 13.29.1

Platform: macOS

[REQUIRED] Test case

#!/usr/bin/env python3

import requests
import json
import sys

def main():
    # Update these values based on your environment and project setup:
    EMULATOR_HOST = "127.0.0.1:54510"  # Where your Firestore/Datastore emulator is running
    PROJECT_ID = "testbed-test"       # Your GCP project ID

    # 1. Construct the Datastore REST API endpoint for "lookup"
    lookup_url = f"http://{EMULATOR_HOST}/v1/projects/{PROJECT_ID}:lookup"

    # 2. Build the request body for the Datastore v1 "lookup"
    #    We use readOptions.newTransaction to start a new read-write transaction
    lookup_payload = {
        "readOptions": {
            "newTransaction": {
                "readWrite": {}
            }
        },
        "keys": [
            {
                "path": [
                    {
                        "kind": "TestKind",
                        "name": "TestKey"
                    }
                ]
            }
        ]
    }

    print("[LOOKUP REQUEST BODY]")
    print(json.dumps(lookup_payload, indent=2))

    # 3. Send the lookup request
    lookup_resp = requests.post(lookup_url, json=lookup_payload)
    print("\n[LOOKUP RESPONSE]")
    print("Status Code:", lookup_resp.status_code)
    print("Body:", lookup_resp.text)

    # 4. Parse out the transaction ID from the lookup response
    #    According to the Datastore docs, if you start a transaction,
    #    the response will include a 'transaction' field.
    if lookup_resp.status_code != 200:
        print("Lookup request failed; cannot proceed.")
        sys.exit(1)

    lookup_data = lookup_resp.json()

    transaction_id = lookup_data.get("transaction")
    if not transaction_id:
        print("No transaction ID returned in lookup response. Exiting.")
        sys.exit(1)

    print(f"\nExtracted Transaction ID: {transaction_id}")

    # 5. Now use this transaction ID in a commit request
    commit_url = f"http://{EMULATOR_HOST}/v1/projects/{PROJECT_ID}:commit"

    # Example mutation: upsert an entity with the same key used in the lookup
    commit_payload = {
        "mode": "TRANSACTIONAL",
        "transaction": transaction_id,
        "mutations": [
            {
                "upsert": {
                    "key": {
                        "partitionId": {
                            "projectId": PROJECT_ID,
                            "namespaceId": "" 
                        },
                        "path": [
                            {
                                "kind": "TestKind",
                                "name": "TestKey"
                            }
                        ]
                    },
                    "properties": {
                        "exampleField": {
                            "stringValue": "Hello from transaction"
                        }
                    }
                }
            }
        ]
    }

    print("\n[COMMIT REQUEST BODY]")
    print(json.dumps(commit_payload, indent=2))

    commit_resp = requests.post(commit_url, json=commit_payload)
    print("\n[COMMIT RESPONSE]")
    print("Status Code:", commit_resp.status_code)
    print("Body:", commit_resp.text)

    
    if commit_resp.status_code == 200:
        commit_data = commit_resp.json()
        print("\nCommit Response JSON:")
        print(json.dumps(commit_data, indent=2))
    else:
        print("Commit request failed.")

if __name__ == "__main__":
    main()

[REQUIRED] Steps to reproduce

When I use firestore emulator in datastore emulator mode to test the example script, it gives error while it works perfectly with Datasatore emulator

[REQUIRED] Expected behavior

Datastore emulator's response is: (the last part of it)

[COMMIT RESPONSE]
Status Code: 200
Body: {
  "mutationResults": [{
    "version": "2"
  }],
  "commitVersion": "2"
}


Commit Response JSON:
{
  "mutationResults": [
    {
      "version": "2"
    }
  ],
  "commitVersion": "2"
}

[REQUIRED] Actual behavior

Firestore emulator's response is:

[COMMIT RESPONSE]
Status Code: 409
Body: {"error":{"code":409,"message":"Transaction lock timeout.","status":"ABORTED"}}
Commit request failed.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions