@@ -71,6 +71,7 @@ def __init__(self, *args, **kwargs):
7171 self .pilotAgentsDB = None
7272 self .taskQueueDB = None
7373 self .storageManagementDB = None
74+ self .sandboxDB = None
7475
7576 # # transformations types
7677 self .transformationTypes = None
@@ -153,6 +154,18 @@ def initialize(self):
153154 except RuntimeError :
154155 pass
155156
157+ # SandboxMetadataDB is optional: used only to unassign a transformation's
158+ # input sandboxes at clean/archive time. A failure here must not stop the
159+ # agent — sandbox unassignment simply becomes a no-op.
160+ try :
161+ result = ObjectLoader ().loadObject ("WorkloadManagementSystem.DB.SandboxMetadataDB" , "SandboxMetadataDB" )
162+ if result ["OK" ]:
163+ self .sandboxDB = result ["Value" ](parentLogger = self .log )
164+ else :
165+ self .log .warn ("Could not load SandboxMetadataDB; sandbox unassignment disabled" , result ["Message" ])
166+ except RuntimeError as excp :
167+ self .log .warn ("Could not connect to SandboxMetadataDB; sandbox unassignment disabled" , str (excp ))
168+
156169 return S_OK ()
157170
158171 #############################################################################
@@ -514,6 +527,7 @@ def archiveTransformation(self, transID):
514527 :param int transID: transformation ID
515528 """
516529 self .log .info (f"Archiving transformation { transID } " )
530+ self ._unassignTransformationSandboxes (transID )
517531 # Clean the jobs in the WMS and any failover requests found
518532 res = self .cleanTransformationTasks (transID )
519533 if not res ["OK" ]:
@@ -531,11 +545,28 @@ def archiveTransformation(self, transID):
531545 self .log .info (f"Updated status of transformation { transID } to Archived" )
532546 return S_OK ()
533547
548+ def _unassignTransformationSandboxes (self , transID ):
549+ """Best-effort removal of a transformation's input-sandbox assignment.
550+
551+ Drops the ``Transformation:<transID>`` mapping in the SandboxMetadataDB so
552+ the sandbox store cleaner can reclaim the (now unused) sandboxes. Never
553+ raises and never returns an error: a sandbox-DB problem must not block
554+ transformation cleaning.
555+
556+ :param int transID: transformation ID
557+ """
558+ if not self .sandboxDB :
559+ return
560+ result = self .sandboxDB .unassignEntities ([f"Transformation:{ transID } " ])
561+ if not result ["OK" ]:
562+ self .log .warn ("Could not unassign sandboxes for transformation" , f"{ transID } : { result ['Message' ]} " )
563+
534564 def cleanTransformation (self , transID ):
535565 """This removes what was produced by the supplied transformation,
536566 leaving only some info and log in the transformation DB.
537567 """
538568 self .log .info ("Cleaning transformation" , transID )
569+ self ._unassignTransformationSandboxes (transID )
539570 res = self .getTransformationDirectories (transID )
540571 if not res ["OK" ]:
541572 self .log .error (
0 commit comments