@@ -68,28 +68,74 @@ def delete_stale_test_instances():
6868
6969
7070def delete_stale_test_databases ():
71- """Delete test databases that are older than four hours."""
71+ """Delete stale or excessive test databases.
72+
73+ Deletes stale test databases that are older than 4 hours and
74+ ensures we don't hit the 100 database limit per spanner instance by
75+ deleting the oldest databases if we are near the limit.
76+ """
7277 cutoff = (int (time .time ()) - 4 * 60 * 60 ) * 1000
7378 instance = CLIENT .instance ("sqlalchemy-dialect-test" )
7479 if not instance .exists ():
7580 return
76- database_pbs = instance .list_databases ()
81+
82+ # Convert iterator to list to allow multiple passes and length check
83+ database_pbs = list (instance .list_databases ())
84+
85+ # First pass: Delete stale databases
86+ remaining_dbs = []
7787 for database_pb in database_pbs :
7888 database = Database .from_pb (database_pb , instance )
7989 # The emulator does not return a create_time for databases.
8090 if database .create_time is None :
91+ remaining_dbs .append (database_pb )
8192 continue
93+
8294 create_time = datetime_helpers .to_milliseconds (database_pb .create_time )
8395 if create_time > cutoff :
96+ remaining_dbs .append (database_pb )
8497 continue
98+
8599 try :
86100 database .drop ()
101+ print (f"Dropped stale database '{ database .database_id } '" )
87102 except ResourceExhausted :
88103 print (
89104 "Unable to drop stale database '{}'. May need manual delete." .format (
90105 database .database_id
91106 )
92107 )
108+ remaining_dbs .append (database_pb ) # Still there
109+
110+ # Second pass: If we are still near the limit (e.g., 90+ databases),
111+ # delete the oldest ones regardless of age to free up slots.
112+ # Spanner instances have a hard limit of 100 databases.
113+ LIMIT = 90
114+ if len (remaining_dbs ) >= LIMIT :
115+ print (f"Database count ({ len (remaining_dbs )} ) is near limit. Cleaning up oldest databases." )
116+
117+ # Sort by creation time
118+ dbs_with_time = []
119+ for db_pb in remaining_dbs :
120+ if db_pb .create_time :
121+ dbs_with_time .append ((db_pb .create_time , db_pb .name ))
122+
123+ dbs_with_time .sort () # Sorts by time ascending (oldest first)
124+
125+ # Delete enough to get below the limit
126+ to_delete = len (remaining_dbs ) - (LIMIT - 10 ) # Aim for 80
127+ deleted_count = 0
128+
129+ for create_time , full_name in dbs_with_time :
130+ if deleted_count >= to_delete :
131+ break
132+ db_id = full_name .split ('/' )[- 1 ]
133+ try :
134+ instance .database (db_id ).drop ()
135+ print (f"Dropped oldest database '{ db_id } ' to prevent resource exhaustion." )
136+ deleted_count += 1
137+ except Exception as e :
138+ print (f"Failed to drop database '{ db_id } ': { e } " )
93139
94140
95141def create_test_instance ():
0 commit comments