Skip to content

feat: add TTL-based eviction to data_svc in-memory RAM store#3324

Open
deacon-mp wants to merge 2 commits into
masterfrom
fix/data-svc-ttl-eviction
Open

feat: add TTL-based eviction to data_svc in-memory RAM store#3324
deacon-mp wants to merge 2 commits into
masterfrom
fix/data-svc-ttl-eviction

Conversation

@deacon-mp
Copy link
Copy Markdown
Contributor

No eviction policy on data_svc.ram. Added configurable TTL eviction to prevent unbounded memory growth. With tests.

Evict finished operations older than 7 days via hourly background task.
@deacon-mp deacon-mp requested a review from Copilot March 16, 2026 03:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a TTL-based eviction mechanism for data_svc’s in-memory ram['operations'] to prevent unbounded growth, along with a unit test covering the eviction predicate.

Changes:

  • Introduces a background async task that periodically evicts finished operations older than a configured TTL.
  • Adds a default TTL configuration for operations (7 days).
  • Adds a unit test validating the eviction filtering logic.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
tests/security/test_ttl_eviction.py Adds a unit test for TTL eviction filtering behavior.
app/service/data_svc.py Adds TTL configuration and a periodic background eviction task for ram['operations'].

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/service/data_svc.py Outdated
Comment on lines +147 to +150
async def load_data(self, plugins=()):
loop = asyncio.get_event_loop()
loop.create_task(self._load(plugins))
loop.create_task(self._evict_expired_objects())
Comment thread app/service/data_svc.py Outdated
Comment on lines +126 to +145
async def _evict_expired_objects(self):
"""Background task to evict expired objects based on TTL config."""
while True:
await asyncio.sleep(3600) # Run every hour
try:
ttl = self._ttl_config.get('operations')
if ttl and 'operations' in self.ram:
now = datetime.datetime.utcnow()
before = len(self.ram['operations'])
self.ram['operations'] = [
op for op in self.ram['operations']
if not (getattr(op, 'finish', None) and
hasattr(op, 'start') and op.start and
(now - op.start).total_seconds() > ttl)
]
evicted = before - len(self.ram['operations'])
if evicted:
self.log.info('TTL eviction: removed %d expired operations', evicted)
except Exception as e:
self.log.error('TTL eviction error: %s', e)
Comment thread app/service/data_svc.py Outdated
Comment on lines +144 to +145
except Exception as e:
self.log.error('TTL eviction error: %s', e)
Comment thread app/service/data_svc.py

class DataService(DataServiceInterface, BaseService):

_DEFAULT_TTL_OPERATION_DAYS = 7
Comment thread app/service/data_svc.py
self.schema = dict(agents=[], planners=[], adversaries=[], abilities=[], sources=[], operations=[],
schedules=[], plugins=[], obfuscators=[], objectives=[], data_encoders=[])
self.ram = copy.deepcopy(self.schema)
self._ttl_config = {'operations': self._DEFAULT_TTL_OPERATION_DAYS * 86400}
Comment thread tests/security/test_ttl_eviction.py Outdated
Comment on lines +24 to +30
operations = [old_op, new_op, running_op]
filtered = [
op for op in operations
if not (getattr(op, 'finish', None) and
hasattr(op, 'start') and op.start and
(now - op.start).total_seconds() > ttl)
]
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
17.6% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

- Use asyncio.get_running_loop() instead of get_event_loop() in load_data()
- Guard _evict_expired_objects() task with self._eviction_task to prevent
  multiple eviction loops if load_data() is called more than once
- Switch eviction exception handler to log.exception() to preserve traceback
- Refactor tests to call _evict_expired_objects() directly instead of
  duplicating the production predicate; add tests for TTL-not-set,
  running operations, and exception-logging paths
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants