-
Notifications
You must be signed in to change notification settings - Fork 4
External callbacks via stomp #1535
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
Changes from 5 commits
27c4f51
7e87816
7070c28
2ba8cee
4cdf50e
a6667df
f72d1f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| from blueapi.client.event_bus import AnyEvent | ||
| from blueapi.core import DataEvent | ||
| from bluesky.run_engine import Dispatcher | ||
| from bluesky_stomp.messaging import MessageContext, StompClient | ||
| from bluesky_stomp.models import MessageTopic | ||
| from event_model import DocumentNames | ||
|
|
||
| from mx_bluesky.common.utils.log import ISPYB_ZOCALO_CALLBACK_LOGGER as LOGGER | ||
|
|
||
| BLUEAPI_EVENT_TOPIC = "public.worker.event" | ||
|
|
||
|
|
||
| class StompDispatcher(Dispatcher): | ||
|
Contributor
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. Could: This seems generic enough that it should live in
Contributor
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. There is an outstanding issue DiamondLightSource/bluesky-stomp#14 - I've referenced this PR in it. Unfortunately this file would introduce a circular dependency between |
||
| def __init__(self, stomp_client: StompClient): | ||
| super().__init__() | ||
| self._client = stomp_client | ||
|
|
||
| def __enter__(self): | ||
| self._subscription_id = self._client.subscribe( | ||
| MessageTopic(name=BLUEAPI_EVENT_TOPIC), self._on_event | ||
| ) | ||
| LOGGER.info("Connecting to stomp broker...") | ||
| self._client.connect() | ||
|
|
||
| def __exit__(self, exc_type, exc_val, exc_tb): | ||
| LOGGER.info("Disconnecting from stomp and unsubscribing...") | ||
| self._client.disconnect() | ||
| self._client.unsubscribe(self._subscription_id) | ||
|
|
||
| def _on_event(self, event: AnyEvent, context: MessageContext): | ||
| match event: | ||
| case DataEvent(name=name, doc=doc): # type: ignore | ||
| self.process(DocumentNames[name], doc) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| from unittest.mock import patch | ||
|
|
||
| from bluesky.callbacks import CallbackBase | ||
| from bluesky_stomp.models import MessageTopic | ||
| from event_model import Event, RunStart, RunStop | ||
|
|
||
| from mx_bluesky.hyperion.external_interaction.callbacks.__main__ import ( | ||
| StompDispatcherContextMgr, | ||
| main, | ||
| ) | ||
| from mx_bluesky.hyperion.parameters.cli import CallbackArgs | ||
|
|
||
| CALLBACK_TOPIC = "callback_test_events" | ||
|
|
||
|
|
||
| class PatchedStompCallbackMgr(StompDispatcherContextMgr): | ||
| def __init__(self, args: CallbackArgs, callbacks: list[CallbackBase]) -> None: | ||
| super().__init__(args, callbacks) | ||
| callback = callbacks[0] | ||
| assert isinstance(callback, StompTestCallback) | ||
| self.callback = callback | ||
|
|
||
| def __enter__(self): | ||
| super().__enter__() | ||
| self.callback.init(self._stomp_client) | ||
| return self | ||
|
|
||
|
|
||
| class StompTestCallback(CallbackBase): | ||
| def __init__(self) -> None: | ||
| super().__init__() | ||
| self.stomp_client = None | ||
| self.destination = MessageTopic(name=CALLBACK_TOPIC) | ||
|
|
||
| def init(self, stomp_client): | ||
| self.stomp_client = stomp_client | ||
| self.fire_event_back("init") | ||
|
|
||
| def start(self, doc: RunStart) -> RunStart | None: | ||
| self.fire_event_back(f"start: {doc['run_name']}") # type: ignore | ||
| return super().start(doc) | ||
|
|
||
| def stop(self, doc: RunStop) -> RunStop | None: | ||
| self.fire_event_back("stop") | ||
| return super().stop(doc) | ||
|
|
||
| def event(self, doc: Event) -> Event: | ||
| self.fire_event_back(f"event: {doc['data']['baton-requested_user']}") | ||
| return super().event(doc) | ||
|
|
||
| def fire_event_back(self, msg: str): | ||
| self.stomp_client.send(destination=self.destination, obj=msg) # type: ignore | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
|
|
||
| def mock_setup_callbacks(): | ||
| return [StompTestCallback()] | ||
|
|
||
| with ( | ||
| patch( | ||
| "mx_bluesky.hyperion.external_interaction.callbacks.__main__.setup_callbacks", | ||
| return_value=mock_setup_callbacks(), | ||
| ), | ||
| patch( | ||
| "mx_bluesky.hyperion.external_interaction.callbacks.__main__.StompDispatcherContextMgr", | ||
| PatchedStompCallbackMgr, | ||
| ), | ||
| ): | ||
| main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should: Feels like we should get this out of
blueapisomewhere, can you add an issue/PR to expose it in blueapi?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DiamondLightSource/blueapi#1343