Skip to content

RDBC-1020 Fix infinite recursion in BeforeDelete and BeforeQuery event args#270

Merged
poissoncorp merged 1 commit intoravendb:v7.2from
redknightlois:RDBC-1020
Apr 10, 2026
Merged

RDBC-1020 Fix infinite recursion in BeforeDelete and BeforeQuery event args#270
poissoncorp merged 1 commit intoravendb:v7.2from
redknightlois:RDBC-1020

Conversation

@redknightlois
Copy link
Copy Markdown
Member

Issue link

https://issues.hibernatingrhinos.com/issue/RDBC-1020

Additional description

BeforeDeleteEventArgs.session and BeforeQueryEventArgs.session properties were returning self.session, causing infinite recursion. Fixed by returning the name-mangled backing attribute directly (_BeforeDeleteEventArgs__session / _BeforeQueryEventArgs__session).

The fix also reworks DeletedEntitiesHolder.__iter__ and __prepare_for_entities_deletion to snapshot the sets before iteration, so BeforeDelete handlers can safely call session.delete() without raising RuntimeError: Set changed size during iteration.

Type of change

  • Bug fix
  • Regression bug fix
  • Optimization
  • New feature

How risky is the change?

  • Low
  • Moderate
  • High
  • Not relevant

Backward compatibility

  • Non breaking change
  • Ensured. Please explain how has it been implemented?
  • Breaking change
  • Not relevant

Is it platform specific issue?

  • Yes. Please list the affected platforms.
  • No

Documentation update

  • This change requires a documentation update. Please mark the issue on YouTrack using Documentation Required tag.
  • No documentation update is needed

Testing by Contributor

  • Tests have been added that prove the fix is effective or that the feature works
  • Internal classes added to the test class (e.g. entity or index definition classes) have the lowest possible access modifier (preferable private)
  • It has been verified by manual testing
  • Existing tests verify the correct behavior

Testing by RavenDB QA team

  • This change requires a special QA testing due to possible performance or resources usage implications (CPU, memory, IO). Please mark the issue on YouTrack using QA Required tag.
  • No special testing by RavenDB QA team is needed

Is there any existing behavior change of other features due to this change?

  • Yes. Please list the affected features/subsystems and provide appropriate explanation
  • No

UI work

  • It requires further work in the Studio. Please mark the issue on YouTrack using Studio Required tag.
  • No UI work is needed

@redknightlois redknightlois changed the title RDBC-1020 RDBC-1020 Fix infinite recursion in BeforeDelete and BeforeQuery event args Feb 26, 2026
@redknightlois redknightlois changed the base branch from v7.1 to v7.2 March 6, 2026 21:12
# Entities added by BeforeDelete handlers (via __on_before_deleted_entities)
# are processed in a second pass once the main set is exhausted.
if self.__on_before_deleted_entities:
for item in list(self.__on_before_deleted_entities):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

could use yield from

)
if command:
self.__throw_invalid_deleted_document_with_deferred_command(command)
# Allow BeforeDelete handlers to call session.delete() without corrupting
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

let's remove this comment or replace it with entire method docstring - it's a commit-specific note

# Allow BeforeDelete handlers to call session.delete() without corrupting
# the iteration: new deletions are staged in __on_before_deleted_entities
# and processed in the second pass of DeletedEntitiesHolder.__iter__.
self._deleted_entities._DeletedEntitiesHolder__prepare_entities_deleted = True
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can be changed to protected field (DeletedEntitiesHolder._prepare_entities_deleted)

Copy link
Copy Markdown
Contributor

@poissoncorp poissoncorp left a comment

Choose a reason for hiding this comment

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

minor changes required, but LGTM

…yEventArgs.session

Both @Property implementations returned `self.session` (calling themselves)
instead of the private backing attribute. Any access caused RecursionError.

Fix: use `self.__session` inside the class body (Python handles name mangling
at definition time), consistent with all other event arg classes. The
explicit-mangled form `self._ClassName__session` is only correct when
accessing private attributes from outside a class.

Also fixes cascade deletes in BeforeDelete handlers: DeletedEntitiesHolder.__iter__
now snapshots both sets with list() before yielding, so session.delete() calls
inside a handler do not raise "Set changed size during iteration". New deletions
are staged in __on_before_deleted_entities and processed in a second pass.

Regression tests verify that:
- BeforeDeleteEventArgs.session and BeforeQueryEventArgs.session return the
  session object without recursion
- A before-delete handler can cascade-delete a second document via args.session.load()
  and args.session.delete()
@poissoncorp poissoncorp merged commit fb3454d into ravendb:v7.2 Apr 10, 2026
9 of 10 checks passed
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