-
Notifications
You must be signed in to change notification settings - Fork 439
Fix panels not receiving latest messages on newly subscribed topic that is already subscribed to by another panel #7113
Conversation
|
||
type Params<T> = { | ||
/** |
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.
commented this because I had to debug the tests and wanted to have a better understanding of the parameters
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.
Not your problem in this PR to fix - but since useMessageReducer
is an internal API I do wonder if it would be a "simple" PR to remove the string[]
variant. Then you can also drop the sidecar preloadType
field.
@@ -358,11 +358,7 @@ describe("MessagePipelineProvider/useMessagePipeline", () => { | |||
}); | |||
expect(result.current.subscriptions).toEqual([{ topic: "/input/foo" }]); | |||
|
|||
// Emit empty player state to process new subscriptions |
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.
no longer need to wait for a player to emit again to receive the last messages on a topic
expect(result.current).toEqual(2); | ||
|
||
rerender({ topics: ["/bar", "/foo"] }); | ||
|
||
// no additional calls |
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.
no longer need player emit to push lastMessagesOnTOpic
packages/studio-base/src/components/MessagePipeline/MockMessagePipelineProvider.tsx
Outdated
Show resolved
Hide resolved
activeData: { | ||
currentTime: { sec: 0, nsec: 0 }, | ||
parameters: new Map([[urdfParamName, URDF3]]), | ||
messages: [ |
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.
was this just broken if these were getting ignored?
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.
^ I too am curious - seems related to your Fixture code update about messages
in activeData
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.
These weren't being ignored before my change, but they weren't going through the normal message pipeline. They were emitted on the initialization of the store, but because there are no subscribers, nothing would handle them. They would not be emitted again because subsequent dispatching to the MP would overwrite it. putting them in the frame
lets them go through the normal messages
mock message pipeline prop
@@ -112,13 +111,11 @@ export const UrdfDisplayMode: StoryObj = { | |||
}, | |||
}; | |||
|
|||
const fixture = useDelayedFixture({ |
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.
did having this break something?
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.
This wasn't breaking anything as of my final implementation, but I believe it was responsible for the failing story in a previous iteration. Since it doesn't do anything anymore I'll keep it as is
|
||
type Params<T> = { | ||
/** |
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.
Not your problem in this PR to fix - but since useMessageReducer
is an internal API I do wonder if it would be a "simple" PR to remove the string[]
variant. Then you can also drop the sidecar preloadType
field.
* @param state - Immutable. `undefined` when called on initialization or seek. Otherwise, the current state. | ||
* @returns - New state. Must be new reference to trigger rerender. | ||
*/ | ||
restore: (state: T | undefined) => T; |
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.
The comment says state is immutable - what makes that so? Does it need to be changed to Immutable<T>
?
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.
Was just trying to portray the original comment, will try to apply Immutable<T>
but might complain in a bunch of places that I don't want to change in this PR
@@ -30,18 +30,37 @@ import { | |||
|
|||
const log = Log.getLogger(__filename); | |||
|
|||
type MessageReducer<T> = (arg0: T, message: MessageEvent) => T; |
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.
fun fact - arg0 comes to us from the earliest days of when I converted the codebase from flow to typescript :D
@@ -124,7 +124,7 @@ describe("PanelExtensionAdapter", () => { | |||
await Promise.resolve(); | |||
}); | |||
expect(renderStates).toEqual([ | |||
{ currentFrame: [message], didSeek: false }, | |||
{ currentFrame: [], didSeek: false }, // first frame is empty because there are no subscribers yet |
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.
If there are no subscribers yet why did the previous version of the test have messages in currentFrame
?
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.
because it would use the custom logic in MMPP that would add all of the existing messages to messagesBySubscriberId
when update-subscriber
was called. This now happens in a separate update-player
action after update-subscribers
was called.
@@ -80,7 +80,10 @@ export type Fixture = { | |||
topics?: Topic[]; | |||
capabilities?: string[]; | |||
profile?: string; | |||
activeData?: Partial<PlayerStateActiveData>; | |||
/** Player active data does not include `messages`. |
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.
What does it mean that it does not include messages
? Is it that any messages you provide in the activeData
fixture are ignored?
activeData: { | ||
currentTime: { sec: 0, nsec: 0 }, | ||
parameters: new Map([[urdfParamName, URDF3]]), | ||
messages: [ |
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.
^ I too am curious - seems related to your Fixture code update about messages
in activeData
@@ -581,11 +572,6 @@ describe("MessagePipelineProvider/useMessagePipeline", () => { | |||
}); | |||
expect(result.current.subscriptions).toEqual([{ topic: "/input/foo" }]); | |||
|
|||
// Emit empty player state to process new subscriptions |
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.
👏 Always happy to see some doubleAct be deleted :D
@@ -62,7 +62,8 @@ export type MessagePipelineInternalState = { | |||
* for dispatching messages needs to iterate over the array of IDs. | |||
*/ | |||
subscriberIdsByTopic: Map<string, string[]>; | |||
newTopicsBySubscriberId: Map<string, Set<string>>; | |||
/** This holds the last message emitted by the player on each topic. Attempt to use this before falling back to player backfill. |
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.
Remind me what it means to fall-back to player backfill in this context?
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.
player backfill reads the last message on all active subscriptions from the file and triggers a seek
@@ -227,36 +228,20 @@ function updateSubscriberAction( | |||
action: UpdateSubscriberAction, |
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.
Github is terrible at letting me comment outside of changed lines but the comment a few lines above this that mentions newTopicsBySubscriberId
is wrong now. You can probably write a better comment on what this function does given the new implementation.
} | ||
} | ||
|
||
const messagesBySubscriberId = new Map<string, MessageEvent[]>(); |
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.
Is SubscriberId
the same ID as newTopicsForId
a few lines up? Both are the subscriber id? How come we have a new map of messages by subscriberId here but the action only has one id
?
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.
If my reading of this is correct - the downsteam impact of this change is that whenever a panel subscribes, all panels will get notified with empty frame data? There is no carry-over of the messagesBySubscriberId
from the existing state. Is that a problem? No test seemed to think it was a problem but it does seem like there's some gap here.
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.
responded in slack, but useMessageReducer
and PanelExtensionAdapter
are memoized by the message array within messagesBySubscriberId
and will not read in a new frame unless that array has changed
User-Facing Changes
Description
Supercedes: #7090
Because "subscriptions" haven't changed according to the underlying player it does not re-emit state. Which means that updatePlayerStateAction on the message pipeline store is never called to set the lastMessages on the newly subscribed topics.
This PR moves the logic for applying lastMessages to subscribed topics to
updateSubscriberAction
to emit these messages immediately instead of waiting for another underlying player emit state. I've removed the need to storenewTopics
across the actions because handling these topics happens entirely in theupdateSubscriberAction
. I've also added some logic to remove messages on topics that are no longer subscribed to fromlastMessageByTopic
so that stale messages are not passed when resubscribing to that topic before backfill resolves.Some notes about reading the PR:
I've removed some useDelayedFixture since they were causing strange behavior with some stories. These shouldn't be necessary anymore since the
MockMessagePipelineProvider
should now handle "Player" lifecycle and doing backfill for initial subscriptions better.I had to add a
pauseFrame
functionality that more closely mirrored player listener behavior to the MMPP so that we wait until all components finish rendering before updating the store.Fixes: FG-5574