Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore: add support for one-way WebSockets to UI#16855

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Parkreiner merged 24 commits intomes/one-way-ws-01frommes/one-way-ws-02
Mar 28, 2025

Conversation

Parkreiner
Copy link
Member

@ParkreinerParkreiner commentedMar 7, 2025
edited
Loading

Closes#16777
Part 2/2, with#16853 handling the backend changes

Changes made

  • AddedOneWayWebSocket utility class to help enforce one-way communication from the server to the client
  • Updated all client client code to use the new WebSocket-based endpoints made to replace the current SSE-based endpoints
  • Updated WebSocket event handlers to be aware of new protocols
  • Refactored existinguseEffect calls and removed some synchronization bugs
  • Removed dependencies and types for dealing with SSEs
  • Addressed some minor Biome warnings

Notes

  • It is a little bit weird to be sending payloads name "ServerSentEvent" over WebSockets, but all the backend engineers I talked to said that it was fine for an initial step towards removing SSEs. I actually think there is value in sending structured data to the client, so the right move might actually be to just rename the type

bpmct reacted with heart emoji
@ParkreinerParkreiner self-assigned thisMar 7, 2025
@ParkreinerParkreiner changed the base branch frommain tomes/one-way-ws-01March 7, 2025 23:11

const connect = (): (() => void) => {
const source = watchAgentMetadata(agent.id);
const createNewConnection = () => {
Copy link
MemberAuthor

Choose a reason for hiding this comment

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

The previouscreate function was super weird because it was responsible for three things

  • Creating a new WebSocket connection from the outside effect
  • Being able to create new connections by calling itself recursively
  • Also acting as auseEffect cleanup function

Figured it'd be better to split up those responsibilities

Comment on lines +12 to +16
const [cachedVersionId, setCachedVersionId] = useState(templateVersionId);
if (cachedVersionId !== templateVersionId) {
setCachedVersionId(templateVersionId);
setLogs([]);
}
Copy link
MemberAuthor

@ParkreinerParkreinerMar 7, 2025
edited
Loading

Choose a reason for hiding this comment

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

This is needed to remove Biome'suseExhaustiveDependencies warning without introducing unnecessary renders

Copy link
Contributor

Choose a reason for hiding this comment

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

This is in regards touseEffect? I think if applicable it'd be better to use a biome comment to ignore linting on the line with an explanation why

// biome-ignore lint/correctness/useExhaustiveDependencies: reasonuseEffect(()=>{if(cachedVersionId!==templateVersionId){setCachedVersionId(templateVersionId);setLogs([]);}},[...]);

Copy link
MemberAuthor

@ParkreinerParkreinerMar 12, 2025
edited
Loading

Choose a reason for hiding this comment

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

Well, the linter warning is actually valid – theuseEffect approach introduces additional renders and has a risk of screen flickering, while the if statement approach avoids all of that

Was mainly calling it out, because while it's the "correct" way to do things (and is shouted out in the React docs), I do think it's an ugly pattern, and you need a lot of context for how React works under the hood to knowwhy it's better than theuseEffect approach

};
}, [options?.onDone, templateVersionId, templateVersionStatus]);
return () => socket.close();
}, [stableOnDone, canWatch, templateVersionId]);
Copy link
MemberAuthor

@ParkreinerParkreinerMar 7, 2025
edited
Loading

Choose a reason for hiding this comment

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

The previous version of the effect was re-synchronizing way too often, because we put a function without a stable memory reference andtemplateVersionStatus directly into the dependency array:

  • Function: Every render would create a new reference and destroy the existing connection for no good reason
  • Status: The value can be a lot of things that indicate that we shouldn't watch (including undefined). Plus, if the status ever switches from pending to running, that's a new value for the array, and triggers a re-sync, destroying a perfectly good connection

Best option seemed to be to wrap the callback, and also collapse the status to a boolean

@@ -1080,7 +1081,7 @@ class ApiMethods {
};

getWorkspaceByOwnerAndName = async (
username = "me",
username: string,
Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Biome was complaining about having default parameters not be at the end of the function signature, but also, we were never calling these functions with an explicit value ofundefined

@Parkreiner
Copy link
MemberAuthor

@brettkolodny Pinging you to make sure this PR didn't miss you, but I caught some Storybook issues that I'm going to try to fix up as soon as I'm done with some meetings

I'll post again once the PR is ready

brettkolodny reacted with thumbs up emoji

if (storybookMetadata !== undefined) {
setMetadata(storybookMetadata);
Copy link
MemberAuthor

Choose a reason for hiding this comment

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

This was removed because it introduces unnecessary renders – better to just usestorybookMetadata as the initial value for the state and avoid a bunch of state syncs

onError: (error) => console.error(error),
onDone: stableOnDone,
onMessage: (newLog) => {
setLogs((current) => [...(current ?? []), newLog]);
Copy link
MemberAuthor

@ParkreinerParkreinerMar 12, 2025
edited
Loading

Choose a reason for hiding this comment

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

Really wanted to just make sure that the logs is always an array, and get rid of theundefined case to make the state updates cleaner, but a bunch of our other components currently depends on that setup

Copy link
Contributor

@brettkolodnybrettkolodny left a comment

Choose a reason for hiding this comment

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

Overall looks good. I'm not used to using type assertions as much as coder does. I think that the "contract" so to speak between the frontend and backend via the generated types and their use within the queries/api code is fine though, and I wonder if we can get the same "contract" for this websocket class. Or maybe that's not worth the effort

Comment on lines +12 to +16
const [cachedVersionId, setCachedVersionId] = useState(templateVersionId);
if (cachedVersionId !== templateVersionId) {
setCachedVersionId(templateVersionId);
setLogs([]);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is in regards touseEffect? I think if applicable it'd be better to use a biome comment to ignore linting on the line with an explanation why

// biome-ignore lint/correctness/useExhaustiveDependencies: reasonuseEffect(()=>{if(cachedVersionId!==templateVersionId){setCachedVersionId(templateVersionId);setLogs([]);}},[...]);

);
export const watchAgentMetadata = (
agentId: string,
): OneWayWebSocket<TypesGen.ServerSentEvent> => {
Copy link
MemberAuthor

@ParkreinerParkreinerMar 12, 2025
edited
Loading

Choose a reason for hiding this comment

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

Sadly, this is the best we can do as far as giving ourselves type-safety (without updating GUTS). It'll be less of an issue for WebSocket connections that don't send SSE-formatted events, but the ServerSentEvent type is structured like this:

// From codersdk/serversentevents.goexportinterfaceServerSentEvent{readonlytype:ServerSentEventType;// empty interface{} type, falling back to unknownreadonlydata:unknown;}

There's no way to pass a type parameter to the type and makedata more specific

@Parkreiner
Copy link
MemberAuthor

@brettkolodny Running into some E2E issues, but I'm still going to request a re-review now because:

  1. The error seems to be for code that has nothing to do with what I touched
  2. The error is a timeout for the GitHub auth logic. I've noticed that GitHub's been really slow for me today, so I'm wondering if this could be connected. I'm going to try again later tonight

@brettkolodny
Copy link
Contributor

Approved for when those tests pass. I've also been having some issues with GitHub today so it could definitely be that

@Parkreiner
Copy link
MemberAuthor

Okay, it was a GitHub hiccup – things are working fine now

@Parkreiner
Copy link
MemberAuthor

Bumping this so it doesn't get closed. Trying to get a backend engineer on the other PR as soon as I can

@ParkreinerParkreiner merged commit8f1eca0 intomes/one-way-ws-01Mar 28, 2025
26 of 30 checks passed
@ParkreinerParkreiner deleted the mes/one-way-ws-02 branchMarch 28, 2025 20:17
@github-actionsgithub-actionsbot locked and limited conversation to collaboratorsMar 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@BrunoQuaresmaBrunoQuaresmaBrunoQuaresma left review comments

@brettkolodnybrettkolodnybrettkolodny approved these changes

Assignees

@ParkreinerParkreiner

Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

3 participants
@Parkreiner@brettkolodny@BrunoQuaresma

[8]ページ先頭

©2009-2025 Movatter.jp