Skip to content

Fix possible race condition in topic common#769

Merged
vgvoleg merged 5 commits intomainfrom
fix_potentional_race_condition
Feb 5, 2026
Merged

Fix possible race condition in topic common#769
vgvoleg merged 5 commits intomainfrom
fix_potentional_race_condition

Conversation

@vgvoleg
Copy link
Collaborator

@vgvoleg vgvoleg commented Feb 5, 2026

Pull request type

Please check the type of change your PR introduces:

  • Bugfix
  • Feature
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Documentation content changes
  • Other (please describe):

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Other information

Copy link

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

This PR attempts to fix a race condition in the shared event loop initialization code in ydb/_topic_common/common.py by replacing a concurrent.futures.Future-based synchronization mechanism with a threading.Event-based approach. Additionally, it updates the flake8 testing dependency from version 3.9.2 to 5.0.0+.

Changes:

  • Replaced concurrent.futures.Future with threading.Event for signaling when the shared event loop is ready
  • Moved the global event loop assignment into the event loop thread and added it before the ready signal
  • Updated flake8 from a pinned version (3.9.2) to a minimum version constraint (>=5.0.0)

Reviewed changes

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

File Description
ydb/_topic_common/common.py Refactored event loop initialization to use threading.Event instead of concurrent.futures.Future for synchronization
test-requirements.txt Updated flake8 version constraint from ==3.9.2 to >=5.0.0

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

Copy link

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

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.


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

Copy link

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

Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.


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

Comment on lines 39 to 73
@@ -60,7 +65,11 @@ def start_event_loop():
)
t.start()

_shared_event_loop = event_loop_set_done.result()
loop_ready.wait()

if _shared_event_loop is None:
raise RuntimeError("Event loop was not properly initialized")

return _shared_event_loop
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

There's a potential data race between the unsynchronized read of _shared_event_loop at line 39 and the write at line 55 (which happens in a different thread outside the lock). While this is likely safe in CPython due to the GIL making reference assignments atomic, it's not guaranteed to be safe in all Python implementations and violates proper synchronization patterns.

Consider capturing the event loop reference in a local variable within the lock and returning that, while still setting the global for future callers. This would eliminate the data race and make the code more robust.

Copilot uses AI. Check for mistakes.
def __eq__(self, other: object) -> bool:
return (
type(self) == type(other) and isinstance(other, YdbRetryOperationSleepOpt) and self.timeout == other.timeout
type(self) is type(other) and isinstance(other, YdbRetryOperationSleepOpt) and self.timeout == other.timeout
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The isinstance check is redundant after type(self) is type(other). If type(self) is type(other) is True, then other must be an instance of YdbRetryOperationSleepOpt (assuming self is). The isinstance check can be safely removed without changing the behavior.

Copilot uses AI. Check for mistakes.
return (
type(self) == type(other)
type(self) is type(other)
and isinstance(other, YdbRetryOperationFinalResult)
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The isinstance check is redundant after type(self) is type(other). If type(self) is type(other) is True, then other must be an instance of YdbRetryOperationFinalResult (assuming self is). The isinstance check can be safely removed without changing the behavior.

Copilot uses AI. Check for mistakes.
@vgvoleg vgvoleg merged commit 810819f into main Feb 5, 2026
40 checks passed
@vgvoleg vgvoleg deleted the fix_potentional_race_condition branch February 5, 2026 13:59
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

Comments