Skip to content

MsgCallbackSubscriber: class-level default Event() is shared between instances #34

Description

@majkelx

Problem

In serverish/messenger/msg_callback_sub.py the stop event is declared as a param with a mutable default created at class definition time:

_stop_event = param.ClassSelector(default=Event(), class_=Event, doc="Event to stop reading messages")

The single Event() instance is evaluated once and becomes the shared default for all MsgCallbackSubscriber instances (and subclasses). Consequences:

  • Calling stop() (or close(), which calls stop()) on one subscriber sets the shared event, which silently terminates the _task_body loop of every other subscriber in the process (if cont is False or self._stop_event.is_set(): break).
  • Since the event is never cleared, any subscriber created after one has been stopped exits its loop on the first received message.
  • Additionally, the Event is bound to whatever event loop first uses it, which can misbehave across loop lifecycles (e.g. in tests).

Fix

Create the event per instance in __init__ instead of as a class-level param default:

def __init__(self, **kwargs) -> None:
    self._stop_event = Event()
    super().__init__(**kwargs)

The new MsgKvSubscriber (KV buckets, feature/kv-buckets branch) already does it this way — MsgCallbackSubscriber should be aligned.

Notes

Worth a quick audit for other mutable param defaults of this kind in the codebase.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions