perf: lazy websocket connection on website

Establishing 1 connection for every website visit is too much.

Only after calling frappe.realtime.on(...) for ANY event, we will
establish a websocket connection.

This is used for handful of things:
- Discussion component
- File upload

Socketio was initially added here: https://github.com/frappe/frappe/pull/6866 this use case no longer exists.

Rarely anywhere website uses realtime.
This commit is contained in:
Ankush Menat 2023-06-30 00:40:55 +05:30
parent e4ec6e65ee
commit be8d2b9de0
11 changed files with 42 additions and 30 deletions

View file

@ -24,7 +24,7 @@ function hide() {
data.value = null;
}
function open_in_editor(location) {
frappe.socketio.socket.emit("open_in_editor", location);
frappe.realtime.emit("open_in_editor", location);
}
function error_component(error, i) {
let location = data.value.error.errors[i].location;
@ -40,7 +40,7 @@ function error_component(error, i) {
template: `<div>${template}</div>`,
methods: {
open() {
frappe.socketio.socket.emit("open_in_editor", location);
frappe.realtime.emit("open_in_editor", location);
}
}
};

View file

@ -31,7 +31,7 @@ frappe.Application = class Application {
}
startup() {
frappe.socketio.init();
frappe.realtime.init();
frappe.model.init();
this.load_bootinfo();

View file

@ -1950,7 +1950,7 @@ frappe.ui.form.Form = class FrappeForm {
let docname = this.docname;
if (this.doc && !this.is_new()) {
frappe.socketio.doc_subscribe(doctype, docname);
frappe.realtime.doc_subscribe(doctype, docname);
}
frappe.realtime.off("docinfo_update");
frappe.realtime.on("docinfo_update", ({ doc, key, action = "update" }) => {

View file

@ -108,7 +108,7 @@ frappe.ui.form.Toolbar = class Toolbar {
}
let rename_document = () => {
if (input_name != docname) frappe.socketio.doctype_subscribe(doctype, input_name);
if (input_name != docname) frappe.realtime.doctype_subscribe(doctype, input_name);
return frappe
.xcall("frappe.model.rename_doc.update_document_title", {
doctype,

View file

@ -1362,7 +1362,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
if (this.list_view_settings?.disable_auto_refresh || this.realtime_events_setup) {
return;
}
frappe.socketio.doctype_subscribe(this.doctype);
frappe.realtime.doctype_subscribe(this.doctype);
frappe.realtime.off("list_update");
frappe.realtime.on("list_update", (data) => {
if (data?.doctype !== this.doctype) {
@ -1385,7 +1385,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
}
disable_realtime_updates() {
frappe.socketio.doctype_unsubscribe(this.doctype);
frappe.realtime.doctype_unsubscribe(this.doctype);
this.realtime_events_setup = false;
}

View file

@ -75,7 +75,7 @@ frappe.call = function (opts) {
var callback = function (data, response_text) {
if (data.task_id) {
// async call, subscribe
frappe.socketio.subscribe(data.task_id, opts);
frappe.realtime.subscribe(data.task_id, opts);
if (opts.queued) {
opts.queued(data);

View file

@ -10,6 +10,7 @@ class RealTimeClient {
on(event, callback) {
if (this.socket) {
this.connect();
this.socket.on(event, callback);
}
}
@ -20,7 +21,19 @@ class RealTimeClient {
}
}
init(port = 9000) {
connect() {
if (this.lazy_connect) {
this.socket.connect();
this.lazy_connect = false;
}
}
emit(event, ...args) {
this.connect();
this.socket.emit(event, ...args);
}
init(port = 9000, lazy_connect = false) {
if (frappe.boot.disable_async) {
return;
}
@ -28,7 +41,7 @@ class RealTimeClient {
if (this.socket) {
return;
}
this.lazy_connect = lazy_connect;
let me = this;
// Enable secure option when using HTTPS
@ -37,11 +50,13 @@ class RealTimeClient {
secure: true,
withCredentials: true,
reconnectionAttempts: 3,
autoConnect: !lazy_connect,
});
} else if (window.location.protocol == "http:") {
this.socket = io(this.get_host(port), {
withCredentials: true,
reconnectionAttempts: 3,
autoConnect: !lazy_connect,
});
}
@ -108,24 +123,22 @@ class RealTimeClient {
}
subscribe(task_id, opts) {
// TODO DEPRECATE
this.socket.emit("task_subscribe", task_id);
this.socket.emit("progress_subscribe", task_id);
this.emit("task_subscribe", task_id);
this.emit("progress_subscribe", task_id);
this.open_tasks[task_id] = opts;
}
task_subscribe(task_id) {
this.socket.emit("task_subscribe", task_id);
this.emit("task_subscribe", task_id);
}
task_unsubscribe(task_id) {
this.socket.emit("task_unsubscribe", task_id);
this.emit("task_unsubscribe", task_id);
}
doctype_subscribe(doctype) {
this.socket.emit("doctype_subscribe", doctype);
this.emit("doctype_subscribe", doctype);
}
doctype_unsubscribe(doctype) {
this.socket.emit("doctype_unsubscribe", doctype);
this.emit("doctype_unsubscribe", doctype);
}
doc_subscribe(doctype, docname) {
if (frappe.flags.doc_subscribe) {
@ -143,18 +156,18 @@ class RealTimeClient {
frappe.flags.doc_subscribe = false;
}, 1000);
this.socket.emit("doc_subscribe", doctype, docname);
this.emit("doc_subscribe", doctype, docname);
this.open_docs.add(`${doctype}:${docname}`);
}
doc_unsubscribe(doctype, docname) {
this.socket.emit("doc_unsubscribe", doctype, docname);
this.emit("doc_unsubscribe", doctype, docname);
return this.open_docs.delete(`${doctype}:${docname}`);
}
doc_open(doctype, docname) {
this.socket.emit("doc_open", doctype, docname);
this.emit("doc_open", doctype, docname);
}
doc_close(doctype, docname) {
this.socket.emit("doc_close", doctype, docname);
this.emit("doc_close", doctype, docname);
}
setup_listeners() {
this.socket.on("task_status_change", function (data) {
@ -194,7 +207,7 @@ class RealTimeClient {
publish(event, message) {
if (this.socket) {
this.socket.emit(event, message);
this.emit(event, message);
}
}
}

View file

@ -56,7 +56,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
if (this.list_view_settings?.disable_auto_refresh) {
return;
}
frappe.socketio.doctype_subscribe(this.doctype);
frappe.realtime.doctype_subscribe(this.doctype);
frappe.realtime.on("list_update", (data) => this.on_update(data));
}

View file

@ -69,14 +69,14 @@ const show_new_topic_modal = (e) => {
};
const setup_socket_io = () => {
frappe.socketio.init(window.socketio_port || "9000");
frappe.socketio.socket.on("publish_message", (data) => {
frappe.realtime.init(window.socketio_port || "9000");
frappe.realtime.on("publish_message", (data) => {
publish_message(data);
});
frappe.socketio.socket.on("update_message", (data) => {
frappe.realtime.on("update_message", (data) => {
update_message(data);
});
frappe.socketio.socket.on("delete_message", (data) => {
frappe.realtime.socket.on("delete_message", (data) => {
delete_message(data);
});
};

View file

@ -653,5 +653,5 @@ $(document).on("page-change", function () {
frappe.ready(function () {
frappe.show_language_picker();
frappe.setup_videos();
frappe.socketio.init(window.socketio_port);
frappe.realtime.init(window.socketio_port, true); // lazy connection
});

View file

@ -56,7 +56,6 @@ function get_site_name(socket) {
conf.default_site &&
["localhost", "127.0.0.1"].indexOf(get_hostname(socket.request.headers.host)) !== -1
) {
// from currentsite.txt since host is localhost
socket.site_name = conf.default_site;
} else if (socket.request.headers.origin) {
socket.site_name = get_hostname(socket.request.headers.origin);