Skip to content

Commit

Permalink
Merge pull request #163 from wbstack/fr/async-request
Browse files Browse the repository at this point in the history
Handle HTTP calls asynchronously, add response caching
  • Loading branch information
m90 committed Jun 21, 2023
2 parents 324e084 + 1b7d653 commit c28d975
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 35 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# queryservice-gateway

## June 2023

- 2.2 - Use asynchronous requests when fetching data from Platform API

## November 2020

- 2.1 - From Github actions build
Expand Down
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@isaacs/ttlcache": "^1.4.0",
"redbird": "^0.9.1",
"url-parse": "^1.5.1",
"xmlhttprequest": "^1.8.0"
Expand Down
90 changes: 59 additions & 31 deletions resolver.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var parse = require('url-parse'),
XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest
TTLCache = require('@isaacs/ttlcache')

var domainForResolver = function domainForResolver(req) {

Expand Down Expand Up @@ -33,45 +34,72 @@ var domainForResolver = function domainForResolver(req) {
}

var defaultResolver = function resolver(host, url, req) {
var wikiDomain = domainForResolver(req)
if (wikiDomain === null) {
return Promise.resolve(null)
}

return fetchWikiForDomain(wikiDomain)
.then(function (response) {
if (!response || !response.data) {
return null
}

let backend = response.data.wiki_queryservice_namespace.backend
let namespace = response.data.wiki_queryservice_namespace.namespace
var parsed = parse('http://' + host + url, true)
parsed.set('pathname', '/bigdata/namespace/' + namespace)
parsed.set('hostname', backend)
// unset the port as it is set in the backend host...
parsed.set('port', '')

return parsed.toString()
})
.catch(function (err) {
console.error(err)
throw err
})

}

// Try and log on failures (so this process keeps running...)
try {
var responseCache = new TTLCache({
ttl: parseInt(process.env.RESPONSE_CACHE_TTL || 60 * 60, 10) * 1000
})

var wikiDomain = domainForResolver(req)
if(wikiDomain === null) {
return null
}
function fetchWikiForDomain (wikiDomain) {
var cachedResponse = responseCache.get(wikiDomain)
if (cachedResponse) {
return Promise.resolve(cachedResponse)
}

// TODO should this be async?! What promise should i be returning...
var xmlHttp = new XMLHttpRequest();
return new Promise(function (resolve, reject) {
var xmlHttp = new XMLHttpRequest()
xmlHttp.open(
"GET",
"http://"+process.env["PLATFORM_API_BACKEND_HOST"]+"/backend/wiki/getWikiForDomain?domain=" + encodeURI(wikiDomain),
false // false for synchronous request
"http://"+process.env["PLATFORM_API_BACKEND_HOST"]+"/backend/wiki/getWikiForDomain?domain=" + encodeURI(wikiDomain)
);
xmlHttp.setRequestHeader("User-Agent", "WBStack - Query Service - Gateway");
xmlHttp.send(null);
var response = JSON.parse(xmlHttp.responseText);

if(!response.data) {
return null
}

let backend = response.data.wiki_queryservice_namespace.backend;
let namespace = response.data.wiki_queryservice_namespace.namespace;
var parsed = parse('http://' + host + url, true);
parsed.set('pathname', '/bigdata/namespace/' + namespace)
parsed.set('hostname', backend)
// unset the port as it is set in the backend host...
parsed.set('port', '')

return parsed.toString()

}
catch (error) {
console.error(error);
}

xmlHttp.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
try {
resolve(JSON.parse(xmlHttp.responseText))
} catch (err) {
reject(err)
}
return
}
reject(
new Error(`Unexpected status code ${this.status} with error: ${xmlHttp.responseText}`)
)
}
};
})
.then(function (response) {
responseCache.set(wikiDomain, response)
return response
})
}

module.exports = {
Expand Down
11 changes: 7 additions & 4 deletions test/defaultResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ var r = require("./../resolver.js")

describe('resolver.defaultResolver', function() {
it('nothing', function() {
assert.strictEqual(
r.defaultResolver('', '', {headers:{}}),
null
);
return Promise.resolve(r.defaultResolver('', '', {headers:{}}))
.then(function (result) {
assert.strictEqual(
result,
null
);
})
});
// TODO make that target backend testable or mockable somehow :)
// it('domain ', function() {
Expand Down

0 comments on commit c28d975

Please sign in to comment.