-
Notifications
You must be signed in to change notification settings - Fork 20
kiwipy/rmq related modules into independent module #297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
7724121
Defer import of aio_pika
unkcpz 97746b4
Explicit future implementation: distinguish concurrent.future.Future …
unkcpz f5e5ec4
Move communication into rmq module
unkcpz c2c9a65
Move TaskRejectError as the common exception for task launch
unkcpz 4dae773
Remove useless communicator param passed to ProcessLaunch __call__
unkcpz 56c18d4
Forming Communicator protocol
unkcpz 2d9fdb9
Remove kiwipy/rmq dependencies of process module
unkcpz 9d6655e
Interface change from communicator -> coordinator
unkcpz f8cc8ed
Remove unnecessary task_send ab from RemoteProcessControl interface
unkcpz 34d3842
Interface for ProcessController
unkcpz bf99d23
RmqCoordinator example to show how using interface can avoid making c…
unkcpz 15b267b
broadcast subscriber has versatile filters
unkcpz 23d954c
Generic typing for Coordinator
unkcpz 46bd2d3
Adopt new message protocol and changes required for aiida-core support
unkcpz 8e23a88
Simpler create_task_threadsafe implementation
unkcpz f3f3095
Remove RmqCoordinator to tests/util only
unkcpz b577f5e
Export plumpy.futures.Future
unkcpz b0877db
Remove first unnecessary `_comm` argument to subscriber
unkcpz 4b0267c
Protocol fulfill for RemoteProcessThreadController
unkcpz c4c50e0
Rename interfaces of Coordinator
unkcpz b1e4e1e
ralex - T -> CommT in generic type at communications.py
unkcpz 14c6348
misc: pre-commit / uv.lock
unkcpz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # -*- coding: utf-8 -*- | ||
| # type: ignore | ||
| import re | ||
| import typing | ||
|
|
||
|
|
||
| class BroadcastFilter: | ||
| """A filter that can be used to limit the subjects and/or senders that will be received""" | ||
|
|
||
| def __init__(self, subscriber, subject=None, sender=None): | ||
| self._subscriber = subscriber | ||
| self._subject_filters = [] | ||
| self._sender_filters = [] | ||
| if subject is not None: | ||
| self.add_subject_filter(subject) | ||
| if sender is not None: | ||
| self.add_sender_filter(sender) | ||
|
|
||
| @property | ||
| def __name__(self): | ||
| return 'BroadcastFilter' | ||
|
|
||
| def __call__(self, body, sender=None, subject=None, correlation_id=None): | ||
agoscinski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if self.is_filtered(sender, subject): | ||
| return None | ||
| return self._subscriber(body, sender, subject, correlation_id) | ||
|
|
||
| def is_filtered(self, sender, subject) -> bool: | ||
| if subject is not None and self._subject_filters and not any(check(subject) for check in self._subject_filters): | ||
| return True | ||
|
|
||
| if sender is not None and self._sender_filters and not any(check(sender) for check in self._sender_filters): | ||
| return True | ||
|
|
||
| return False | ||
|
|
||
| def add_subject_filter(self, subject_filter): | ||
| self._subject_filters.append(self._ensure_filter(subject_filter)) | ||
|
|
||
| def add_sender_filter(self, sender_filter): | ||
| self._sender_filters.append(self._ensure_filter(sender_filter)) | ||
|
|
||
| @classmethod | ||
| def _ensure_filter(cls, filter_value): | ||
| if isinstance(filter_value, str): | ||
| return re.compile(filter_value.replace('.', '[.]').replace('*', '.*')).match | ||
| if isinstance(filter_value, typing.Pattern): # pylint: disable=isinstance-second-argument-not-valid-type | ||
| return filter_value.match | ||
|
|
||
| return lambda val: val == filter_value | ||
|
|
||
| @classmethod | ||
| def _make_regex(cls, filter_str): | ||
| """ | ||
| :param filter_str: The filter string | ||
| :type filter_str: str | ||
| :return: The regular expression object | ||
| """ | ||
| return re.compile(filter_str.replace('.', '[.]')) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| # -*- coding: utf-8 -*- | ||
| from __future__ import annotations | ||
|
|
||
| from collections.abc import Sequence | ||
| from typing import Any, Hashable, Optional, Protocol, Union, runtime_checkable | ||
|
|
||
| from plumpy import loaders | ||
| from plumpy.message import MessageType | ||
| from plumpy.utils import PID_TYPE | ||
|
|
||
| ProcessResult = Any | ||
| ProcessStatus = Any | ||
|
|
||
|
|
||
| @runtime_checkable | ||
| class ProcessController(Protocol): | ||
| """ | ||
| Control processes using coroutines that will send messages and wait | ||
| (in a non-blocking way) for their response | ||
| """ | ||
|
|
||
| def get_status(self, pid: 'PID_TYPE') -> ProcessStatus: | ||
| """ | ||
| Get the status of a process with the given PID | ||
| :param pid: the process id | ||
| :return: the status response from the process | ||
| """ | ||
| ... | ||
|
|
||
| def pause_process(self, pid: 'PID_TYPE', msg_text: str | None = None) -> Any: | ||
| """ | ||
| Pause the process | ||
|
|
||
| :param pid: the pid of the process to pause | ||
| :param msg: optional pause message | ||
| :return: True if paused, False otherwise | ||
| """ | ||
| ... | ||
|
|
||
| def pause_all(self, msg_text: str | None) -> None: | ||
| """Pause all processes that are subscribed to the same coordinator | ||
|
|
||
| :param msg_text: an optional pause message text | ||
| """ | ||
| ... | ||
|
|
||
| def play_process(self, pid: 'PID_TYPE') -> ProcessResult: | ||
| """Play the process | ||
|
|
||
| :param pid: the pid of the process to play | ||
| :return: True if played, False otherwise | ||
| """ | ||
| ... | ||
|
|
||
| def play_all(self) -> None: | ||
| """Play all processes that are subscribed to the same coordinator""" | ||
|
|
||
| def kill_process(self, pid: 'PID_TYPE', msg_text: str | None = None) -> Any: | ||
| """Kill the process | ||
|
|
||
| :param pid: the pid of the process to kill | ||
| :param msg: optional kill message | ||
| :return: True if killed, False otherwise | ||
| """ | ||
| ... | ||
|
|
||
| def kill_all(self, msg_text: Optional[str]) -> None: | ||
| """Kill all processes that are subscribed to the same coordinator | ||
|
|
||
| :param msg: an optional pause message | ||
| """ | ||
| ... | ||
|
|
||
| def notify_msg(self, msg: MessageType, sender: Hashable | None = None, subject: str | None = None) -> None: | ||
| """ | ||
| Notify all processes by broadcasting of a msg | ||
|
|
||
| :param msg: an optional pause message | ||
| """ | ||
|
|
||
| def continue_process( | ||
| self, pid: 'PID_TYPE', tag: Optional[str] = None, nowait: bool = False, no_reply: bool = False | ||
| ) -> Union[None, PID_TYPE, ProcessResult]: | ||
| """Continue the process | ||
|
|
||
| :param _communicator: the communicator | ||
| :param pid: the pid of the process to continue | ||
| :param tag: the checkpoint tag to continue from | ||
| """ | ||
| ... | ||
|
|
||
| def launch_process( | ||
| self, | ||
| process_class: str, | ||
| init_args: Optional[Sequence[Any]] = None, | ||
| init_kwargs: Optional[dict[str, Any]] = None, | ||
| persist: bool = False, | ||
| loader: Optional[loaders.ObjectLoader] = None, | ||
| nowait: bool = False, | ||
| no_reply: bool = False, | ||
| ) -> Union[None, PID_TYPE, ProcessResult]: | ||
| """Launch a process given the class and constructor arguments | ||
|
|
||
| :param process_class: the class of the process to launch | ||
| :param init_args: the constructor positional arguments | ||
| :param init_kwargs: the constructor keyword arguments | ||
| :param persist: should the process be persisted | ||
| :param loader: the classloader to use | ||
| :param nowait: if True, don't wait for the process to send a response, just return the pid | ||
| :param no_reply: if True, this call will be fire-and-forget, i.e. no return value | ||
| :return: the result of launching the process | ||
| """ | ||
| ... | ||
|
|
||
| def execute_process( | ||
| self, | ||
| process_class: str, | ||
| init_args: Optional[Sequence[Any]] = None, | ||
| init_kwargs: Optional[dict[str, Any]] = None, | ||
| loader: Optional[loaders.ObjectLoader] = None, | ||
| nowait: bool = False, | ||
| no_reply: bool = False, | ||
| ) -> Union[None, PID_TYPE, ProcessResult]: | ||
| """Execute a process. This call will first send a create task and then a continue task over | ||
| the communicator. This means that if communicator messages are durable then the process | ||
| will run until the end even if this interpreter instance ceases to exist. | ||
|
|
||
| :param process_class: the process class to execute | ||
| :param init_args: the positional arguments to the class constructor | ||
| :param init_kwargs: the keyword arguments to the class constructor | ||
| :param loader: the class loader to use | ||
| :param nowait: if True, don't wait for the process to send a response | ||
| :param no_reply: if True, this call will be fire-and-forget, i.e. no return value | ||
| :return: the result of executing the process | ||
| """ | ||
| ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # -*- coding: utf-8 -*- | ||
| from __future__ import annotations | ||
|
|
||
| from re import Pattern | ||
| from typing import TYPE_CHECKING, Any, Callable, Hashable, Protocol, runtime_checkable | ||
|
|
||
| if TYPE_CHECKING: | ||
| ID_TYPE = Hashable | ||
| Receiver = Callable[..., Any] | ||
|
|
||
|
|
||
| @runtime_checkable | ||
| class Coordinator(Protocol): | ||
| def hook_rpc_receiver( | ||
| self, | ||
| receiver: 'Receiver', | ||
| identifier: 'ID_TYPE | None' = None, | ||
| ) -> Any: ... | ||
|
|
||
| def hook_broadcast_receiver( | ||
| self, | ||
| receiver: 'Receiver', | ||
| subject_filters: list[Hashable | Pattern[str]] | None = None, | ||
| sender_filters: list[Hashable | Pattern[str]] | None = None, | ||
| identifier: 'ID_TYPE | None' = None, | ||
| ) -> Any: ... | ||
|
|
||
| def hook_task_receiver( | ||
| self, | ||
| receiver: 'Receiver', | ||
| identifier: 'ID_TYPE | None' = None, | ||
| ) -> 'ID_TYPE': ... | ||
|
|
||
| def unhook_rpc_receiver(self, identifier: 'ID_TYPE | None') -> None: ... | ||
|
|
||
| def unhook_broadcast_receiver(self, identifier: 'ID_TYPE | None') -> None: ... | ||
|
|
||
| def unhook_task_receiver(self, identifier: 'ID_TYPE') -> None: ... | ||
|
Comment on lines
+14
to
+38
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I rename the interfaces to distinguish the coordinator from rmq communicator. |
||
|
|
||
| def rpc_send( | ||
| self, | ||
| recipient_id: Hashable, | ||
| msg: Any, | ||
| ) -> Any: ... | ||
|
|
||
| def broadcast_send( | ||
| self, | ||
| body: Any | None, | ||
| sender: 'ID_TYPE | None' = None, | ||
| subject: str | None = None, | ||
| correlation_id: 'ID_TYPE | None' = None, | ||
| ) -> Any: ... | ||
|
|
||
| def task_send(self, task: Any, no_reply: bool = False) -> Any: ... | ||
|
|
||
| def close(self) -> None: ... | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.