Skip to content
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

feat(extensions): Broadcast Channel API #10527

Merged
merged 3 commits into from
May 23, 2021

Conversation

crowlKats
Copy link
Member

Current approach is wrong and doesn't work

Copy link
Contributor

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

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

I'm getting BorrowMutErrors when I try to postMessage. I'll investigate.

thread 'main' panicked at 'already borrowed: BorrowMutError', runtime/metrics.rs:189:35

extensions/broadcast_channel/01_broadcast_channel.js Outdated Show resolved Hide resolved
@bnoordhuis bnoordhuis force-pushed the broadcast_channel branch 3 times, most recently from c71d60a to c220bcd Compare May 15, 2021 18:45
@bnoordhuis bnoordhuis force-pushed the broadcast_channel branch 2 times, most recently from 7735044 to 8fc6262 Compare May 16, 2021 14:29
Copy link
Contributor

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

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

@lucacasonato This is ready for review. I've left some comments.

.arg("--location")
.arg("http://127.0.0.1/")
.arg("--allow-read")
.arg("--no-check") // TS typechecking makes the test hang.
Copy link
Contributor

Choose a reason for hiding this comment

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

Because it tries to typecheck the inline script.

Comment on lines +93 to +92
// Defer to avoid starving the event loop. Not using queueMicrotask()
// for that reason: it lets promises make forward progress but can
// still starve other parts of the event loop.
Copy link
Contributor

Choose a reason for hiding this comment

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

I observe that with queueMicrotask() e.g. setTimeout() callbacks don't run when ping-ponging messages over a BroadcastChannel.

extensions/web/02_event.js Show resolved Hide resolved
tools/wpt.ts Outdated Show resolved Hide resolved
Copy link
Member

@lucacasonato lucacasonato left a comment

Choose a reason for hiding this comment

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

As always, implementation is very clean. Nice work. Mostly just some nitpicks.

I do want to voice some concerns regarding how the resources work. Currently there is one broadcast channel resource for all BroadcastChannels in an isolate. This is unfortunate because it makes the resource sanitizer in tests less effective. Say you create a BC outside a test, then another one in a test, and you don't close the one in the test, then there will be no resource leakage warning. I assume this approach is a lot faster though, because less boundary crossings, so this isn't a blocker for me. Logically one resource per BroadcastChannel would make more sense for me though.

extensions/broadcast_channel/01_broadcast_channel.js Outdated Show resolved Hide resolved
extensions/broadcast_channel/01_broadcast_channel.js Outdated Show resolved Hide resolved
extensions/broadcast_channel/01_broadcast_channel.js Outdated Show resolved Hide resolved
@@ -0,0 +1,97 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
Copy link
Member

Choose a reason for hiding this comment

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

What about feature flagging this entire file, and enabling it by default?

extensions/broadcast_channel/lib.rs Outdated Show resolved Hide resolved
extensions/broadcast_channel/lib.rs Outdated Show resolved Hide resolved
extensions/web/02_event.js Show resolved Hide resolved
tools/wpt.ts Outdated Show resolved Hide resolved
@bnoordhuis
Copy link
Contributor

Currently there is one broadcast channel resource for all BroadcastChannels in an isolate.

It's for reasons of correctness, not performance - that's just a happy accident. :-)

WPT requires that messages are delivered to receivers in subscription order but tokio::sync::broadcast doesn't make that guarantee (and indeed doesn't seem to work that way.)

If you feel really strongly, I could implement a tokio::sync::broadcast with stronger ordering guarantees, but that means more code and complexity.

@lucacasonato
Copy link
Member

If you feel really strongly, I could implement a tokio::sync::broadcast with stronger ordering guarantees, but that means more code and complexity.

Nope, with this background info it makes sense now. Lets leave it as is.

@bnoordhuis
Copy link
Contributor

@lucacasonato How do I get the linter to pass? It's using an existing deno binary that doesn't know about the new BroadcastChannel global... Catch-22.

@lucacasonato
Copy link
Member

lucacasonato commented May 18, 2021

@bnoordhuis Fixed now through merging #10652. Just merge with main / rebase

@bnoordhuis
Copy link
Contributor

The integration test appears to be hanging on the CI but I can't reproduce locally, it always passes (and in less than a second):

2021-05-19T22:28:52.2896211Z test integration::broadcast_channel has been running for over 60 seconds

I've added an #[ignore] to see if it fares better.

@bnoordhuis
Copy link
Contributor

All green with the integration test disabled.

@lucacasonato Ideas on how to move forward? I don't mind investigating further but I don't have any leads and I'd like to get this merged before the inevitable next round of merge conflicts.

@@ -2715,6 +2715,25 @@ console.log("finish");
assert!(end - start < Duration::new(10, 0));
}

#[test]
#[ignore] // Hangs on CI, passes locally.
fn broadcast_channel() {
Copy link
Member

Choose a reason for hiding this comment

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

So this is a integration test instead of a JS unit test because it requires --ignore?

Copy link
Contributor

Choose a reason for hiding this comment

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

Because it requires --location.

Copy link
Member

Choose a reason for hiding this comment

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

Oh... don't we run unit tests with --location? If not, @bartlomieju any objections to doing that?

Copy link
Contributor

Choose a reason for hiding this comment

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

We do:

--location=http://js-unit-tests/foo/bar

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I remember the other issue: the test hangs when run as a unit test because deno test tries to type-check the embedded script. I guess I'll move it to a separate file.

Copy link
Member

Choose a reason for hiding this comment

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

@bnoordhuis I can get the test to pass without --no-check.

@lucacasonato
Copy link
Member

I will take a quick look and see if I can get it to fail / pass, but if not let's merge it and investigate later.

@caspervonb
Copy link
Contributor

caspervonb commented May 20, 2021

Deadlock somewhere? haven't read through the implementation yet but test hangs for me.

image

@lucacasonato
Copy link
Member

Found it - wrong assumption about worker startup being sync.

@bnoordhuis
Copy link
Contributor

Thanks for helping debug. I've turned it into a unit test and Luca pointed out how to fix the race.

constructor(name) {
super();

window.location;
Copy link
Member

Choose a reason for hiding this comment

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

This should be done in Rust.

@lucacasonato
Copy link
Member

lucacasonato commented May 20, 2021

Tried it out locally, and seems to work well. I have just two concerns left to address now:

  1. this should be --unstable until we decide about cross process or not
  2. the --location check and origin namespacing should happen generically in rust, because other implementers might not have a window origin

@bnoordhuis
Copy link
Contributor

I've added a --unstable check in op_broadcast_subscribe(). That's the main entry point.

Since it's behind --unstable now and because I don't want to think about --location too much, I've simply ripped out the window.location check.

Replaces the file-backed provider by an in-memory one because proper
file locking is a hard problem that detracts from the proof of concept.

Teach the WPT runner how to extract tests from .html files because all
the relevant tests in test_util/wpt/webmessaging/broadcastchannel are
inside basics.html and interface.html.
Copy link
Member

@lucacasonato lucacasonato left a comment

Choose a reason for hiding this comment

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

LGTM - the origin handling is incorrect (as shown by the broken WPT), but that is fine for now. We will need to revisit it when we do cross process BroadcastChannel.

Thanks for sitting through this @bnoordhuis :-)

@bnoordhuis bnoordhuis merged commit af15463 into denoland:main May 23, 2021
@bnoordhuis
Copy link
Contributor

Sorry @crowlKats, something went wrong while merging. I used rebase-without-squash with the intent of keeping you as the author of the first commit but for some reason I show up as the author. Mea culpa.

@crowlKats crowlKats deleted the broadcast_channel branch September 29, 2021 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants