Repro (current main)
cache_set/v1.py and cache_get/v1.py store a process-global map in WorkflowMemoryCache keyed by video_metadata.video_identifier. Cleanup is __del__ and only remembers self.namespace, which run() overwrites every call:
# cache_set/v1.py on main
def __del__(self):
if self.namespace:
WorkflowMemoryCache.clear_namespace(self.namespace)
# run():
self.namespace = namespace # last video wins
Sequence: set on vidA, then vidB, then the block is destroyed → vidA stays in WorkflowMemoryCache.cache for the process lifetime.
Confirmed by reading origin/main (self.namespace = namespace + __del__ clears only that one).
Why it matters
Class-level dict, no bound. A long-running workflow that sees many video ids leaks one namespace per extra video. Not a crash on the first video; unbounded growth after that.
Fix
#2834 — retain every namespace the instance touched; release all on close/__del__; refcount so two instances sharing a video id do not smash each other.
Repro (current
main)cache_set/v1.pyandcache_get/v1.pystore a process-global map inWorkflowMemoryCachekeyed byvideo_metadata.video_identifier. Cleanup is__del__and only remembersself.namespace, whichrun()overwrites every call:Sequence: set on
vidA, thenvidB, then the block is destroyed →vidAstays inWorkflowMemoryCache.cachefor the process lifetime.Confirmed by reading
origin/main(self.namespace = namespace+__del__clears only that one).Why it matters
Class-level dict, no bound. A long-running workflow that sees many video ids leaks one namespace per extra video. Not a crash on the first video; unbounded growth after that.
Fix
#2834 — retain every namespace the instance touched; release all on close/
__del__; refcount so two instances sharing a video id do not smash each other.