Use fetch instead of axios to close connections in SQLEditor, ERD, Schema Diff and Debugger to ensure it completes. When closing a browser tab, axios does not guarantee AJAX request completion. #5894

This commit is contained in:
Aditya Toshniwal 2023-03-20 18:20:48 +05:30 committed by GitHub
parent 64aa739224
commit b923f5fcfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 77 additions and 70 deletions

View File

@ -47,3 +47,14 @@ export function parseApiError(error) {
return error;
}
}
export function callFetch(url, options, headers={}) {
return fetch(url, {
...options,
headers: {
'Content-type': 'application/json',
[pgAdmin.csrf_token_header]: pgAdmin.csrf_token,
...headers,
}
});
}

View File

@ -427,17 +427,6 @@ export default class DebuggerModule {
setDebuggerTitle(panel, browser_preferences, label, newTreeInfo.schema.label, db_label, null, self.pgBrowser);
panel.focus();
// Register Panel Closed event
panel.on(self.wcDocker.EVENT.CLOSED, function () {
let closeUrl = url_for('debugger.close', {
'trans_id': trans_id,
});
self.api({
url: closeUrl,
method: 'DELETE',
});
});
panel.on(self.wcDocker.EVENT.RENAME, function (panel_data) {
self.panel_rename_event(panel_data, panel, treeInfo);
});
@ -607,17 +596,6 @@ export default class DebuggerModule {
panel.focus();
// Panel Closed event
panel.on(self.wcDocker.EVENT.CLOSED, function () {
let closeUrl = url_for('debugger.close', {
'trans_id': res.data.data.debuggerTransId,
});
self.api({
url: closeUrl,
method: 'DELETE',
});
});
// Panel Rename event
panel.on(self.wcDocker.EVENT.RENAME, function (panel_data) {
self.panel_rename_event(panel_data, panel, treeInfo);

View File

@ -741,16 +741,6 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
setDebuggerTitle(panel, browser_pref, label, treeInfo.schema.label, treeInfo.database.label, null, pgAdmin.Browser);
panel.focus();
// Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function () {
let closeUrl = url_for('debugger.close', {
'trans_id': res_post.data.data.debuggerTransId,
});
api({
url: closeUrl,
method: 'DELETE',
});
});
/* TO-DO check how to add this is new lib for wc-docker */
commonUtils.registerDetachEvent(panel);

View File

@ -17,7 +17,7 @@ import Loader from 'sources/components/Loader';
import Layout, { LayoutHelper } from '../../../../../static/js/helpers/Layout';
import EventBus from '../../../../../static/js/helpers/EventBus';
import getApiInstance from '../../../../../static/js/api_instance';
import getApiInstance, { callFetch } from '../../../../../static/js/api_instance';
import Notify from '../../../../../static/js/helpers/Notifier';
import { evalFunc } from '../../../../../static/js/utils';
@ -380,6 +380,27 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev
.catch(raiseJSONError);
messages(params.transId);
}
const closeConn = ()=>{
/* Using fetch with keepalive as the browser may
cancel the axios request on tab close. keepalive will
make sure the request is completed */
callFetch(
url_for('debugger.close', {
'trans_id': params.transId,
}), {
keepalive: true,
method: 'DELETE',
}
)
.then(()=>{/* Success */})
.catch((err)=>console.error(err));
};
window.addEventListener('unload', closeConn);
return ()=>{
window.removeEventListener('unload', closeConn);
};
}, []);
const setUnsetBreakpoint = (res, breakpoint_list) => {

View File

@ -8,26 +8,6 @@ try {
function(pgDirectDebug, pgAdmin) {
var pgDebug = window.pgAdmin.Tools.Debugger;
pgDebug.load(document.getElementById('debugger-main-container'), {{ uniqueId }}, {{ debug_type }}, '{{ function_name_with_arguments }}', '{{layout|safe}}');
// Register unload event on window close.
/* If opened in new tab, close the connection only on tab/window close and
* not on refresh attempt because the user may cancel the reload
*/
if(window.opener) {
$(window).on('unload', function(ev) {
$.ajax({
method: 'DELETE',
url: "{{ url_for('debugger.index') }}close/{{ uniqueId }}"
});
});
} else {
$(window).on('beforeunload', function(ev) {
$.ajax({
method: 'DELETE',
url: "{{ url_for('debugger.index') }}close/{{ uniqueId }}"
});
});
}
},
function() {
console.log(arguments);

View File

@ -31,7 +31,7 @@ import { MainToolBar } from './MainToolBar';
import { Box, withStyles } from '@material-ui/core';
import EventBus from '../../../../../../static/js/helpers/EventBus';
import { ERD_EVENTS } from '../ERDConstants';
import getApiInstance, { parseApiError } from '../../../../../../static/js/api_instance';
import getApiInstance, { callFetch, parseApiError } from '../../../../../../static/js/api_instance';
import { openSocket, socketApiGet } from '../../../../../../static/js/socket_instance';
/* Custom react-diagram action for keyboard events */
@ -333,12 +333,22 @@ class ERDTool extends React.Component {
});
window.addEventListener('unload', ()=>{
this.apiObj.delete(url_for('erd.close', {
trans_id: this.props.params.trans_id,
sgid: this.props.params.sgid,
sid: this.props.params.sid,
did: this.props.params.did
}));
/* Using fetch with keepalive as the browser may
cancel the axios request on tab close. keepalive will
make sure the request is completed */
callFetch(
url_for('erd.close', {
trans_id: this.props.params.trans_id,
sgid: this.props.params.sgid,
sid: this.props.params.sid,
did: this.props.params.did
}), {
keepalive: true,
method: 'DELETE',
}
)
.then(()=>{/* Success */})
.catch((err)=>console.error(err));
});
let done = await this.initConnection();

View File

@ -19,7 +19,7 @@ import { Box, makeStyles } from '@material-ui/core';
import { Results } from './Results';
import { SchemaDiffCompare } from './SchemaDiffCompare';
import EventBus from '../../../../../static/js/helpers/EventBus';
import getApiInstance from '../../../../../static/js/api_instance';
import getApiInstance, { callFetch } from '../../../../../static/js/api_instance';
import { useModal } from '../../../../../static/js/helpers/ModalProvider';
export const SchemaDiffEventsContext = createContext();
@ -78,9 +78,19 @@ export default function SchemaDiffComponent({params}) {
function registerUnload() {
window.addEventListener('unload', ()=>{
api.delete(url_for('schema_diff.close', {
trans_id: params.transId
}));
/* Using fetch with keepalive as the browser may
cancel the axios request on tab close. keepalive will
make sure the request is completed */
callFetch(
url_for('schema_diff.close', {
trans_id: params.transId
}), {
keepalive: true,
method: 'DELETE',
}
)
.then(()=>{/* Success */})
.catch((err)=>console.error(err));
});
}

View File

@ -16,7 +16,7 @@ import { ResultSet } from './sections/ResultSet';
import { StatusBar } from './sections/StatusBar';
import { MainToolBar } from './sections/MainToolBar';
import { Messages } from './sections/Messages';
import getApiInstance, {parseApiError} from '../../../../../static/js/api_instance';
import getApiInstance, {callFetch, parseApiError} from '../../../../../static/js/api_instance';
import url_for from 'sources/url_for';
import { PANELS, QUERY_TOOL_EVENTS, CONNECTION_STATUS } from './QueryToolConstants';
import { useInterval } from '../../../../../static/js/custom_hooks';
@ -359,11 +359,19 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
useEffect(()=>{
const closeConn = ()=>{
api.delete(
/* Using fetch with keepalive as the browser may
cancel the axios request on tab close. keepalive will
make sure the request is completed */
callFetch(
url_for('sqleditor.close', {
'trans_id': qtState.params.trans_id,
})
);
}), {
keepalive: true,
method: 'DELETE',
}
)
.then(()=>{/* Success */})
.catch((err)=>console.error(err));
};
window.addEventListener('unload', closeConn);

View File

@ -10,7 +10,7 @@ import ERDCore from 'pgadmin.tools.erd/erd_tool/ERDCore';
import * as createEngineLib from '@projectstorm/react-diagrams';
import TEST_TABLES_DATA from './test_tables';
import { FakeLink, FakeNode } from './fake_item';
import { PortModelAlignment, PathFindingLinkFactory } from '@projectstorm/react-diagrams';
import { PortModelAlignment } from '@projectstorm/react-diagrams';
describe('ERDCore', ()=>{
let eleFactory = jasmine.createSpyObj('nodeFactories', {
@ -45,7 +45,6 @@ describe('ERDCore', ()=>{
beforeAll(()=>{
spyOn(createEngineLib, 'default').and.returnValue(erdEngine);
spyOn(PathFindingLinkFactory.prototype, 'calculateRoutingMatrix').and.callFake(()=>{/* intentionally empty */});
});
it('initialization', ()=>{