In high-churn data tracking platforms, clients register and delete millions of ephemeral task records daily. If your database schema allocates standard 64-bit auto-incrementing integer IDs to these documents, you will consume ID space rapidly. While 64-bit ID exhaustion seems unlikely, Google App Engine's NDB ID generator skips ranges to avoid conflicts, hastening exhaustion risks. Building a recycler registry allows us to reclaim and reallocate deleted entity IDs safely.
By utilizing transaction-safe locks and recycling registries in Cloud Datastore, we can prevent entity ID space exhaustion.
1. Creating the Reclaimable ID Registry
We define a Datastore entity model to track recycled IDs and implement transaction-safe functions to claim them during write tasks:
# id_recycler.py
from google.cloud import ndb
class RecycledId(ndb.Model):
# Store reclaimed integer keys
reclaimed_id = ndb.IntegerProperty(required=True)
reclaimed_at = ndb.DateTimeProperty(auto_now_add=True)
class EphemeralTask(ndb.Model):
task_name = ndb.StringProperty()
created_at = ndb.DateTimeProperty(auto_now_add=True)
@ndb.transactional(xg=True)
def allocate_next_task_id(task_name):
# Query for an available recycled ID
query = RecycledId.query().order(RecycledId.reclaimed_at)
available_id_entity = query.get()
if available_id_entity:
target_id = available_id_entity.reclaimed_id
# Delete from registry to prevent double allocation
available_id_entity.key.delete()
print(f"Allocating recycled ID: {target_id}")
else:
# Fall back to standard ID generation if registry is empty
target_id = None
# Create the task entity
if target_id:
task_key = ndb.Key(EphemeralTask, target_id)
task = EphemeralTask(key=task_key, task_name=task_name)
else:
task = EphemeralTask(task_name=task_name)
task.put()
return task.key.id()
2. Reclaiming IDs on Document Deletion
When a document is marked for deletion, we write its ID to the recycler registry within the same transaction to guarantee data integrity.