Auto-save does not always work

Hi,
We are running JupyterLab with JupyterHub - all on K8s.
Many users run their environments and some of them complain about auto-save is not “always working”
One of the cases:

I was working till 08:59 (at my desk), when off to a meeting (a network event)
Open my laptop for a few minutes around 2024-03-12 09:49
Went back to my station and noticed around 2024-03-12 10:06 that stuff I was doing earlier were not saved.

It seems like user was working on the same notebook while moving from network to network and the latter changes were not saved using auto-save

Our env:

IPython          : 8.12.3
ipykernel        : 6.29.3
ipywidgets       : 8.0.3
jupyter_client   : 8.6.0
jupyter_core     : 5.7.1
jupyter_server   : 2.4.0
jupyterlab       : 4.0.12
nbclient         : 0.8.0
nbconvert        : 7.16.2
nbformat         : 5.9.0
notebook         : 6.5.4
qtconsole        : 5.4.3
traitlets        : 5.14.1
  • No visible errors in Jupyter Lab UI or K8s pod logs
  • Not auto-save logs for the file changed and expected to be saved
  • Environment was responsive and working “as usual”

Any assitance will be appreciated

1 Like

We had this problem and in our case it was a networking issue, that is, after briefly shutting / sleeping the laptop we were getting briefly the warning Server unavailable even if the server was on. After getting this message autosave is deactivated and doesn’t work anymore and you need to restart your server.

I will check with my team if we can contribute this upstream, I can’t share the code directly due to company policy, but our solution consisted on updating the connection lost handler.

2 Likes

Thanks for the info , it indeed maybe the case as users do report getting Server unavailable message after connection is restored they do click Dismiss and continue to work.
Do you know what is the Restart button do in this prompt, it seems like it just refreshes the page - can Restart cause loosing the changes?
Screenshot 2024-03-25 at 12.49.46

Did you check if you can contribute on your fix?
Did you change and build your own Jupyterlab or you provided is somehow externally overriding the default handler?
What was the change in logic of the handler?
Thanks

2 Likes

We are allowed to contribute a fix for this! Let’s see if we can have it ready next week

I believe the restart button sends you to hub UI. In our case, the users were losing changes after they open again their laptops and not realising that autosave was not working properly.

Did you change and build your own Jupyterlab or you provided is somehow externally overriding the default handler?

We don’t build our own jupyterlab, we added the change through extensions by overriding the default handler.

What was the change in logic of the handler?

The handler itself is not an issue, the issue comes from the autosave interval increasing to hours after the connection is lost, which isn’t ideal. Our fix is currently in the handler because we have some extra features implemented.

1 Like

I am super excited you can contribute your fix,
Can you explain how exactly to do you extension override, I tried to try customize the handler but I cannot find the proper way to override and/or build it.
Let say I would just change the text of the current prompt, how can I change and override the extension?
Screenshot 2024-03-27 at 14.55.06

Thank you

1 Like

Supposing that you have already created a jupyterlab extension (otherwise follow this tutorial) you can update index.ts with this basic example:

(This example adds the disconnect handler on top of an existing extension, it could go alone if needed)

import {
  IConnectionLost,
  JupyterFrontEnd,
  JupyterFrontEndPlugin,
  JupyterLab
} from '@jupyterlab/application';
import { ServerConnection, ServiceManager } from '@jupyterlab/services';
import { Widget } from '@lumino/widgets';
import { Dialog } from '@jupyterlab/apputils';

namespace PluginIDs {
  export const plugin = 'my_extension:plugin';
  export const connectionHandler = 'my_extension:connection-handler';
}

const plugin: JupyterFrontEndPlugin<void> = {
  id: PluginIDs.plugin,
  description: 'my_extension extension for jupyterlab',
  autoStart: true,
  requires: [],
  activate: async (app: JupyterFrontEnd) => {
    console.log('JupyterLab extension my_extension is activated!');

    // Your extension
  }
};

const connectionHandler: JupyterFrontEndPlugin<IConnectionLost> = {
  id: PluginIDs.connectionHandler,
  autoStart: true,
  requires: [JupyterLab.IInfo],
  activate: async (
    app: JupyterFrontEnd,
    info: JupyterLab.IInfo
  ): Promise<IConnectionLost> => {
    console.log(
      'JupyterLab extension my_extension_connection_handler is activated!'
    );

    // We display this dialog to users whenever the connection is lost
    const content = new Widget();
    content.node.innerHTML = `<p>Information that you want to write</p>`;
    const dialog = new Dialog({
      title: 'Server Unavailable',
      body: content,
      buttons: []
    });

    const connectionHandler: IConnectionLost = async (
      manager: ServiceManager.IManager,
      _: ServerConnection.NetworkError
    ) => {
      if (dialog.isVisible && !info.isConnected) {
        return;
      }
      dialog.launch();
    };
    return connectionHandler;
  },
  provides: IConnectionLost
};

export default [plugin, connectionHandler] as JupyterFrontEndPlugin<any>[];

You will need to also disable the previous handler by adding this in package.json

"disabledExtensions": [
   "@jupyterlab/hub-extension:connectionlost"
]

Update <p>Information that you want to write</p> with whatever information that you want to show

1 Like