Skip to content

Allow customizing the ServiceManager with plugins #16794

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

Merged
merged 7 commits into from
Feb 19, 2025

Conversation

jtpio
Copy link
Member

@jtpio jtpio commented Sep 19, 2024

References

Fixes #15329
Fixes #12504
Replaces #16556
Replaces #16783
Closes #16141
Depends on #16804

More references:

Motivation

See #15329 (comment)

Code changes

  • Update to the latest @lumino packages
  • Resolve the service manager service first, then start the lab application
  • Try with IDefaultDrive and IContentsManager
  • Move all the underlying ServiceManager services to their own plugins
  • Create a more explicit ServiceManagerPlugin plugin type
  • Use a separate PluginRegistry for service manager plugins? Or the same one as regular plugins?
    • A different one clearly separates the two phases of plugin activation
    • The same one would allow regular plugins to consume service manager plugins, for example requiring IKernelManager instead of app.serviceManager.kernels.
  • Handle IConnectionStatus
  • Add a section in the extension dev documentation about "Service Manager Plugins"
  • Add to the user / developer changelog for visibility? Postponing for now
  • Create a new @jupyterlab/services-extension package to host the service manager plugins
  • Mock package test (usage)

This can be tested using this example extension, which disables @jupyterlab/application-extension:default-drive and replaces with its own implementation: https://github.com/jtpio/jupyterlab-custom-service-manager-plugins

Example providing a custom default drive

image

Example providing a custom ContentsManager that logs each get call

import {
  Contents,
  ContentsManager,
  IContentsManager,
  ServiceManagerPlugin
} from '@jupyterlab/services';

class CustomContents extends ContentsManager {
  async get(
    path: string,
    options?: Contents.IFetchOptions
  ): Promise<Contents.IModel> {
    console.log('CustomContents.get', path);
    return super.get(path, options);
  }
}

const contentsPlugin: ServiceManagerPlugin<Contents.IManager> = {
  id: 'myextension:contents-drive',
  description: 'A JupyterLab extension providing a custom contents manager',
  autoStart: true,
  provides: IContentsManager,
  activate: (_: null): Contents.IManager => {
    console.log('Using a CUSTOM contents manager plugin');
    return new CustomContents();
  }
};

export default [
  contentsPlugin,
];

image

User-facing changes

None

Backwards-incompatible changes

None

Copy link

Thanks for making a pull request to jupyterlab!
To try out this branch on binder, follow this link: Binder

@afshin
Copy link
Member

afshin commented Feb 5, 2025

The office hours exist for members of the community to come ask questions from members of the EC. If the question requires following up or further decisions to be made, then normal procedure will follow.

From my point of view, this is a case of a decision that should be made within the Jupyter Frontends Council by the members of this subproject. I imagine if you come to office hours, you might make the case that this particular technical decision on whether to merge a specific feature-related PR in the JupyterLab code base should be made by the EC. I don't agree with this interpretation, but you're obviously free to make that case tomorrow.

Nonetheless, I again strongly encourage you to come today to the appropriate meeting to discuss this and to make one final case after all this discussion. I don't believe EC office hours is the correct venue to talk about a JupyterLab PR.

@afshin
Copy link
Member

afshin commented Feb 5, 2025

@echarles, you stated:

In the meantime, I expect this PR to not be merged whatever result would come from the vote you have opened.

After months of discussion:

  • Not a single other member of the Jupyter Frontends Council has objected to merging this PR and a few have already approved it.
  • Not a single other member of the Jupyter Frontends Council has seconded your motion to put this PR to a vote.
  • The Jupyter Security Subproject has spent an entire meeting discussing whether your security claims have merit and they have decided this feature does not pose an objectionable risk.

You wish to appeal to a body (the Jupyter Executive Council) that does not adjudicate technical decisions made by subprojects. That is absolutely your right, but I don't think included in that right is the ability to yet again stall motion on a feature simply because you alone object to it.

@echarles
Copy link
Member

echarles commented Feb 5, 2025

The discussion has moved from technical to governance, the governance aspect is the topic I am willing to share with the executive council. I hope enough people will be there tomorrow, and in all case, I will request a follow-up so the case is shared with all the members of the executive council.

@afshin
Copy link
Member

afshin commented Feb 5, 2025

If you have governance-related questions, as you indicate, please feel free to raise them at the Executive Council's office hours tomorrow.

If you have any further conversation you'd like to have about this PR, please feel free to join today's call where this PR and its resolution will be a topic of discussion.

@echarles
Copy link
Member

echarles commented Feb 5, 2025

I can not join today call, and also diccussed 2 days ago during a call with @jtpio. I would like to say again tomorrow topic will be the invalidity of the vote, so I expect the JupyterLab council @jupyterlab/jupyterlab-council to continue discussing but not merge this PR until the governance point is treated by the Jupyter Executive council.

@SylvainCorlay
Copy link
Member

so I expect the JupyterLab council @jupyterlab/jupyterlab-council to continue discussing but not merge this PR until the governance point is treated by the Jupyter Executive council.

I don't think this is a fair expectation at this point.

@afshin
Copy link
Member

afshin commented Feb 5, 2025

@echarles stated:

I would like to say again tomorrow topic will be the invalidity of the vote

There was no vote. I mistakenly asked people to vote in discussion thread. Four people did. Then Eric questioned whether voting with a secret ballot was even allowed (NB: it is). So I re-read the decision-making guide myself to see if there's anything against a secret ballot. There isn't.

But there is a requirement that someone else seconds your motion to call a vote. No one has. No one else has objected to merging this PR. No one else in the Frontends Council has recommended calling a vote. All the other indications (the votes that came in before I asked if anyone even supports holding such a vote and also the approvals on this PR) are positive.

(NB: David Q and Rick W did say that as members of the Security subproject, they think a vote on this would be okay. But they weren't saying that as voters in this body.)

So strictly speaking, you're right. That discussion vote was invalid. It was invalid because no one but Eric wanted to vote on it. And given the support it got in that poll and in this PR, I imagine that even if someone on the council did second the motion to hold a vote, the PR would still be accepted.

@fcollonval
Copy link
Member

Hey all,

I will second @echarles to go for a public vote. I think it is important for heated subject that the decision should be clear and public to reflect the open-minded and transparent decision process of this community.
As @afshin pointed out, the discussion with the poll opened in the council repository was not meant to be a formal vote. It would be good to reboot the vote via an issue on the team compass repository with a ping to the council member asking to vote.

@echarles
Copy link
Member

echarles commented Feb 5, 2025

Thank you @fcollonval

@afshin I have opened a vote jupyterlab/frontends-team-compass#273

So I re-read the decision-making guide myself to see if there's anything against a secret ballot. There isn't.

@afshin to me there is. Let's discuss about that tomorrow.

@jupyterlab/jupyterlab-council Please vote on jupyterlab/frontends-team-compass#273 - you should have been tagged in the vote itself. Please also consider https://github.com/jupyterlab/council/discussions/28 as closed (if you don't know about that discussion, that is also fine and logical, as you have not been tagged on it, so quite hard to vote without even being invited)

cc/ Executive Council @afshin @Ruv7 @ellisonbg @fperez @jasongrout @Zsailer (as discussed, I will join tomorrow 06 Feb call).

@Zsailer
Copy link
Member

Zsailer commented Feb 5, 2025

Cross referencing a reply I made on the other thread, realizing I should have posted here: jupyterlab/frontends-team-compass#273 (comment)

The reason we need this PR is because I made a design decision, which I later came to regret, back in 2019 when I initially jupyterlab/jupyterlab#5845.
In this initial implementation, the API required all Jupyter frontends to ship with a serviceManager instead of making service managers plugins.

I have one anecdotal piece of evidence where the old ServiceManager design decision blocked me (sorry @afshin 😉).

I tried to create a new (RTC-enabled) Notebook-like application that gave JupyterLab user's a link to share to a single document in their server for (real-time) collaborative editing only (no kernel execution allowed). Invitees would get access to only that document, in a single document Notebookv7 view to collaborate on the document's content. The requirements were:

  1. the UI was a stripped down Notebook v7, just used for editing the content of the notebook.
  2. should only talk to the host's contents and y-doc websocket APIs.
  3. No access to the host's kernels, kernelspecs, terminals, sessions, etc.
  4. Still include many of the plugins, like TOC, ipywidgets, vega, jupyter-collaboration etc.

In the idea case, I would have just liked to use Notebook v7 with a configurable ServiceManager class to replace the parts I needed (note that I do need a "replacement" here, not just an API for addition). Instead, the hard-coded ServiceManager posed a problem for me; it hardcodes all Jupyter Server APIs and expects all of the services to working. It also automatically polls the kernelspecs APIs (any sessions?) on a regular interval. While we can use server auth to prevent access to these APIs, the client constantly dumps errors due to this polling behavior. On the other hand, there was no way to stop this unwanted behavior without creating a new app from scratch. Ultimately, this is what I did, and it led to a lot of extra duplicate logic.

Under the proposed PR, I would get what I needed much easier. There may be different approaches we could take, but this PR seems reasonable to me. Just making the current servicemanager "expandable" using providers doesn't feel quite enough and I haven't seen a strong argument on why we shouldn't other than perceived risk of API scope creep.

Just sharing one, personal use-case outside of just JupyterLite.

@Zsailer
Copy link
Member

Zsailer commented Feb 5, 2025

Maybe one improvement that would help address some of @echarles usability concerns is to consider some way to dump out the plugin dependency graph, so if a user reports some unexpected behavior because on conflicting plugins, we can more easily trace the issue?

@echarles
Copy link
Member

echarles commented Feb 6, 2025

cc/ Executive Council (as discussed, I will join tomorrow 06 Feb call).

A valid vote being now opened, I will thus not join today Executive council to discuss this case cc/ Executive Council @afshin @Ruv7 @ellisonbg @fperez @jasongrout @Zsailer

Copy link
Member

@krassowski krassowski left a comment

Choose a reason for hiding this comment

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

I noted a tiny typo, otherwise good!

// Populate application info.
this._info = { ...JupyterLab.defaultInfo, ...info };
this._info = new JupyterLab.Info(options);
Copy link
Member

Choose a reason for hiding this comment

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

Note to self: this will prevent writing to some attributes, but it's ok because it is private

Co-authored-by: Michał Krassowski <5832902+krassowski@users.noreply.github.com>
@jtpio
Copy link
Member Author

jtpio commented Feb 13, 2025

Thanks @krassowski for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Split ServiceManager into multiple plugins Allow extending the kernel / service / session manager using an extension