Configure client side query timeout (#610)

* Configure client side query timeout
* Update test command on windows
* Make query timeout cli opt an uint
* Fix windows test command
* Check for updates when rendering connection page
* Fix typo
This commit is contained in:
Dan Sosedoff 2022-12-08 15:07:40 -06:00 committed by GitHub
parent 0008842a68
commit 7557ac854e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 30 deletions

View File

@ -507,7 +507,13 @@ func GetBookmarks(c *gin.Context) {
// GetInfo renders the pgweb system information // GetInfo renders the pgweb system information
func GetInfo(c *gin.Context) { func GetInfo(c *gin.Context) {
successResponse(c, command.Info) successResponse(c, gin.H{
"app": command.Info,
"features": gin.H{
"session_lock": command.Opts.LockSession,
"query_timeout": command.Opts.QueryTimeout,
},
})
} }
// DataExport performs database table export // DataExport performs database table export

View File

@ -49,7 +49,7 @@ type Options struct {
ConnectHeaders string `long:"connect-headers" description:"List of headers to pass to the connect backend"` ConnectHeaders string `long:"connect-headers" description:"List of headers to pass to the connect backend"`
DisableConnectionIdleTimeout bool `long:"no-idle-timeout" description:"Disable connection idle timeout"` DisableConnectionIdleTimeout bool `long:"no-idle-timeout" description:"Disable connection idle timeout"`
ConnectionIdleTimeout int `long:"idle-timeout" description:"Set connection idle timeout in minutes" default:"180"` ConnectionIdleTimeout int `long:"idle-timeout" description:"Set connection idle timeout in minutes" default:"180"`
QueryTimeout int `long:"query-timeout" description:"Set global query execution timeout in seconds" default:"0"` QueryTimeout uint `long:"query-timeout" description:"Set global query execution timeout in seconds" default:"300"`
Cors bool `long:"cors" description:"Enable Cross-Origin Resource Sharing (CORS)"` Cors bool `long:"cors" description:"Enable Cross-Origin Resource Sharing (CORS)"`
CorsOrigin string `long:"cors-origin" description:"Allowed CORS origins" default:"*"` CorsOrigin string `long:"cors-origin" description:"Allowed CORS origins" default:"*"`
BinaryCodec string `long:"binary-codec" description:"Codec for binary data serialization, one of 'none', 'hex', 'base58', 'base64'" default:"none"` BinaryCodec string `long:"binary-codec" description:"Codec for binary data serialization, one of 'none', 'hex', 'base58', 'base64'" default:"none"`

View File

@ -1,3 +1,5 @@
var appInfo = {};
var appFeatures = {};
var editor = null; var editor = null;
var connected = false; var connected = false;
var bookmarks = {}; var bookmarks = {};
@ -57,10 +59,13 @@ function getPagesCount(rowsCount) {
} }
function apiCall(method, path, params, cb) { function apiCall(method, path, params, cb) {
var timeout = 300000; // 5 mins is enough var timeout = appFeatures.query_timeout;
if (timeout == null) {
timeout = 300; // in seconds
}
$.ajax({ $.ajax({
timeout: timeout, timeout: timeout * 1000, // in milliseconds
url: "api" + path, url: "api" + path,
method: method, method: method,
cache: false, cache: false,
@ -68,12 +73,10 @@ function apiCall(method, path, params, cb) {
headers: { headers: {
"x-session-id": getSessionId() "x-session-id": getSessionId()
}, },
success: function(data) { success: cb,
cb(data);
},
error: function(xhr, status, data) { error: function(xhr, status, data) {
if (status == "timeout") { if (status == "timeout") {
return cb({ error: "Query timeout after " + (timeout / 1000) + "s" }); return cb({ error: "Query timeout after " + timeout + "s" });
} }
cb(jQuery.parseJSON(xhr.responseText)); cb(jQuery.parseJSON(xhr.responseText));
@ -82,6 +85,7 @@ function apiCall(method, path, params, cb) {
} }
function getInfo(cb) { apiCall("get", "/info", {}, cb); } function getInfo(cb) { apiCall("get", "/info", {}, cb); }
function getConnection(cb) { apiCall("get", "/connection", {}, cb); }
function getObjects(cb) { apiCall("get", "/objects", {}, cb); } function getObjects(cb) { apiCall("get", "/objects", {}, cb); }
function getTables(cb) { apiCall("get", "/tables", {}, cb); } function getTables(cb) { apiCall("get", "/tables", {}, cb); }
function getTableRows(table, opts, cb) { apiCall("get", "/tables/" + table + "/rows", opts, cb); } function getTableRows(table, opts, cb) { apiCall("get", "/tables/" + table + "/rows", opts, cb); }
@ -644,7 +648,7 @@ function showConnectionPanel() {
$("#input").hide(); $("#input").hide();
$("#body").addClass("full"); $("#body").addClass("full");
apiCall("get", "/connection", {}, function(data) { getConnection(function(data) {
var rows = []; var rows = [];
for(key in data) { for(key in data) {
@ -994,23 +998,16 @@ function getLatestReleaseInfo(current) {
} }
function showConnectionSettings() { function showConnectionSettings() {
// Fetch server info // Show the current postgres version
getInfo(function(data) { $(".connection-settings .version").text("v" + appInfo.version).show();
if (data.error) return;
if (!data.version) return;
// Show the current postgres version // Check github release page for updates
$(".connection-settings .version").text("v" + data.version).show(); getLatestReleaseInfo(appInfo);
// Check for updates if running the actual release from Github
if (data.git_sha == "") {
getLatestReleaseInfo(data);
}
});
getBookmarks(function(data) { getBookmarks(function(data) {
// Do not add any bookmarks if we've got an error // Do not add any bookmarks if we've got an error
if (data.error) { if (data.error) {
console.log("Cant get bookmarks:", data.error);
return; return;
} }
@ -1713,6 +1710,7 @@ $(document).ready(function() {
initEditor(); initEditor();
addShortcutTooltips(); addShortcutTooltips();
bindDatabaseObjectsFilter();
// Set session from the url // Set session from the url
var reqUrl = new URL(window.location); var reqUrl = new URL(window.location);
@ -1723,25 +1721,33 @@ $(document).ready(function() {
window.history.pushState({}, document.title, window.location.pathname); window.history.pushState({}, document.title, window.location.pathname);
} }
apiCall("get", "/connection", {}, function(resp) { getInfo(function(resp) {
if (resp.error) { if (resp.error) {
connected = false; alert("Unable to fetch app info: " + resp.error + ". Please reload the browser page.");
showConnectionSettings(); return;
$(".connection-actions").show();
} }
else {
appInfo = resp.app;
appFeatures = resp.features;
getConnection(function(resp) {
if (resp.error) {
connected = false;
showConnectionSettings();
$(".connection-actions").show();
return;
}
connected = true; connected = true;
loadSchemas(); loadSchemas();
$("#current_database").text(resp.current_database); $("#current_database").text(resp.current_database);
$("#main").show(); $("#main").show();
if (!resp.session_lock) { if (!appFeatures.session_lock) {
$(".connection-actions").show(); $(".connection-actions").show();
} }
} });
}); });
bindDatabaseObjectsFilter();
}); });