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

[WIP] Initial support for the interrupt button #460

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

brendan0powers
Copy link

References

#459

Code changes

User-facing changes

No user visible changes. The only effect should be the interrupt button working as epxected.

Backwards-incompatible changes

None

Remaining Issues

@github-actions
Copy link
Contributor

lite-badge 👈 Try it on ReadTheDocs

@jtpio
Copy link
Member

jtpio commented Jan 28, 2022

Thanks @brendan0powers for starting this!

declare global {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface Window {
crossOriginIsolated: boolean | undefined;
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we find a more canonical source for this type? or at least document where this magic variable comes from. At the very least, we'd want to move it out of the implementation, and probably in a dedicated .d.ts somewhere...

Copy link
Author

Choose a reason for hiding this comment

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

I'll move this to the declarations.d.ts for now. Types for crossOriginIsolated were added in typescript 4.4. microsoft/TypeScript-DOM-lib-generator#1029

I'm happy to find another way to do this as well, if you have any suggestions.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like upstream is on:

 "typescript": "~4.5.2",

This would probably be separate PR, and we should have a look at what other goodies we can get any new from static analysis tooling.

if (!window.crossOriginIsolated) {
console.warn(
'JupyterLite is not running in a cross origin isolated context. The interrupt button will not function. Details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements'
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd probably use a tick-delimited string and break it up over multiple lines) so it can pass the linter... and it (along with many other constants) should probably be made internationalizable (but I wouldn't worry about it on this PR).

One approach might be to link to our some of our own, perhaps-not-yet-written documentation for this, as we can put it in a little more context.

Again, the average user is not going to open up the console to see this, so we may want to put this someplace else as well, e.g. the in-app kernel-focused log console... and potentially open it here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hm... it's still rather a deep dive to figure out how this might be effectively set. Some ideas:

  • add something to the docs (maybe in deploying.md) about how one might set the appropriate headers
  • update serve.py to set the appropriate headers so we can evaluate something happening on e.g. binder
    • probably put it behind a flag, e.g. --enable-shared-buffer
    • if this won't work over HTTP (even/especially on localhost), we can figure out some way to make it https with e.g. trustme

Copy link
Author

Choose a reason for hiding this comment

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

I'll add some documentation to deployment.md, and look into adding a flag as you suggest. Logging to the log console seems like a good idea. Should the log be printed on kernel startup, or when the stop button is pressed?

@@ -412,6 +419,10 @@ self.onmessage = async (event: MessageEvent): Promise<void> => {
results = commClose(messageContent);
break;

case 'set-interrupt-buffer':
Copy link
Collaborator

Choose a reason for hiding this comment

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

hm... i don't know if the intent of this API was to closely map to the kernel messaging spec. Ideally, there would be some way to model this on top of jupyter primitives instead of adding a new message type.

Copy link
Author

Choose a reason for hiding this comment

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

This is pretty low level, and i'm not sure it's well suited for the comms API. Especially since I'm not sure what would happen if you passed a SharedArrayBuffer to python and back. I can certainly test that though, if you think we should.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Right, there are some limits to what will work (and across what boundaries, see #463) and not everything is going to map perfectly, but as the first "custom" message on this pipe, it's worth taking a look. If we could use these buffers directly, that might be great for e.g. #195.

Perhaps we need to further differentiate the types of messages... it would be lovely for us to be able to: first distinguish between:

  • "well-known" kernel message types from JupyterLab
    • ... and be able to use more typescript types from upstream, and maybe (ab)use totality checks in the switch
  • "custom" jupyterlite ones
    • there might be a class of ones that all lite kernels might need, e.g. what is the root of the lite site
    • per-kernel ones...

Copy link
Author

Choose a reason for hiding this comment

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

I'm not sure where to go from here. Do you have any concrete suggestions on an approach?

@brendan0powers
Copy link
Author

@bollwyvl Do you have any thoughts on how we could make the CORS errors more visible to the user? My preferred approach would be to gray out the stop button, remove it entirely, or show a dialog. Putting the error message in the kernel log would be better than the browser console, but I'm still not sure users would notice it.

Also, I'm not sure how much freedom we have to alter the Jupyter UI.

@bollwyvl
Copy link
Collaborator

bollwyvl commented Feb 1, 2022

CORS errors more visible to the user

yeah, there's a whole class of issues in these deployment scenarios that are... hard to describe in user-relatable terms. As you say, the ideal is removing things that don't work...

gray out the stop button

...It may be possible... some command control surfaces (e.g. command palette, menu items) support an isEnabled callback... but i don't know about buttons. Also, a big chunk of stuff around buttons is landing upstream in JupyterLab 3.3... and the perhaps might still be time to sneak in some more features.

how much freedom we have

ha, we basically have infinite freedom: it's just a question of how long we want to maintain something that's divergent from upstream.

@brendan0powers
Copy link
Author

@bollwyvl I'm waiting on pyodide/pyodide#2142, but in the meantime, I'd like to push this forward. Do you have an idea of what you'd like to see in order for this PR to be merged?

@bollwyvl bollwyvl mentioned this pull request Feb 13, 2022
3 tasks
@@ -14,3 +14,12 @@ declare let _pipliteUrls: string[];
declare let _disablePyPIFallback: boolean;
declare let pyodide: any;
declare let loadPyodide: any;

// eslint-disable-next-line @typescript-eslint/naming-convention
interface WindowOrWorkerGlobalScope {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We synced the typescript version with the upstream, so you should be able to remove the extra typing.

@bollwyvl bollwyvl mentioned this pull request Mar 17, 2022
11 tasks
@bollwyvl
Copy link
Collaborator

Perhaps this will help: https://github.com/pyodide/pyodide/pull/2332/files

@bollwyvl
Copy link
Collaborator

bollwyvl commented Apr 9, 2022 via email

@brendan0powers
Copy link
Author

Perhaps this will help: https://github.com/pyodide/pyodide/pull/2332/files

It's great to see these patches making their way upstream, unfortunately, it doesn't change the way interrupts work.

@brendan0powers
Copy link
Author

After fiddling with a few different ways of displaying an error, I've settled on simply printing to the notebook when the interrupt button is clicked.
Interrupt Button Error

This has the advantage of notifying the user that something is wrong immediately upon clicking the button. The user may not be in a position to resolve the issue, but they will at least have a useful error message to forward to the maintainer of site.

While implementing this, a few things came up:

  • Clicking the interrupt button while the kernel is starting up will cause kernel startup to fail. This silently breaks the session, and the user cannot execute code. I've worked around this by adding a new _kernelStarted promise, as well as a new type of event to go with it. This adds a second new message type, which is less than ideal.
  • I had to modify the message for setting the interrupt buffer so that it did not return a reply from the worker, otherwise it would cause the first cell to finish executing early in some cases.

Like you mentioned earlier, it seems like we might need a more elegant way to handle the "out of band" messages. I don't think using comms for this would be appropriate, since some of these actions need to happen before the kernel is fully ready.

Oh, also I tested setting the headers on localhost, and it works. I must have done something incorrectly with my previous tests. This means you don't need special Chrome flags or SSL to test, just the headers. I wonder if it would make sense to set the by default when using the jupyterlite CLI tool?

@bollwyvl
Copy link
Collaborator

There is now a service worker available as of #655, which might enable more of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants