Skip to content

Commit

Permalink
perf: improve boot time and remove traverse from deps
Browse files Browse the repository at this point in the history
* Use custom algo for finding services in protos
* Further improvements to proto scan
* Remove console.time statements
* Correct comment
* Conform to style guide
* Don't check for defined in isService since we do that beforehand
  • Loading branch information
sjoerddal-pti authored Oct 13, 2021
1 parent d6707c1 commit 3a95b51
Show file tree
Hide file tree
Showing 4 changed files with 380 additions and 68 deletions.
4 changes: 2 additions & 2 deletions lib/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class Mali extends Emitter {
proto = grpc.loadPackageDefinition(pd)
}

const data = mu.getServiceDefintions(proto)
const data = mu.getServiceDefinitions(proto)

if (!name) {
name = Object.keys(data)
Expand Down Expand Up @@ -402,7 +402,7 @@ class Mali extends Emitter {
* app.close()
*/
async close () {
await Promise.all(this.servers.map(({server}) => server.tryShutdownAsync()))
await Promise.all(this.servers.map(({ server }) => server.tryShutdownAsync()))
}

/**
Expand Down
120 changes: 75 additions & 45 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const traverse = require('traverse')
const CallType = require('@malijs/call-types')

const METHOD_PROPS = ['name', 'options', 'type', 'requestStream', 'responseStream',
Expand Down Expand Up @@ -30,47 +29,86 @@ function getCallTypeFromDescriptor (descriptor) {
}
}

function getServiceDefintions (proto) {
function getDesiredMethodProps (method) {
return METHOD_PROPS.reduce((accumulator, currentKey) => {
accumulator[currentKey] = method[currentKey]
return accumulator
}, {})
}

function getServiceDefinitions (proto) {
const services = {}

traverse(proto).forEach(function (v) {
if (isService(v)) {
const srviceObj = v.service || v
const vKeys = Object.keys(srviceObj)
const name = getServiceNameFromPath(srviceObj[vKeys[0]].path)
const visited = new Set()
const queue = [proto]

if (services[name]) {
return
// Traverses the entire proto object looking for service definitions.
while (queue.length > 0) {
const current = queue.pop()

if (visited.has(current)) {
continue
}

for (const entry of Object.values(current)) {
// Skip null / undefined
if (!entry) {
continue
}

const shortServiceName = getShortServiceNameFromPath(srviceObj[vKeys[0]].path)
// Service definitions may consist of classes or objects
if (typeof entry !== 'object' && typeof entry !== 'function') {
continue
}

services[name] = {
shortServiceName: shortServiceName,
fullServiceName: name,
service: srviceObj,
methods: {}
// These objects won't contain services.
if (entry.type && typeof entry.type !== 'object') {
continue
}

for (const k in srviceObj) {
const m = srviceObj[k]
services[name].methods[m.path] = METHOD_PROPS.reduce((acc, method) => {
if (method !== 'name') {
acc[method] = m[method]
}
return acc
}, {
name: getMethodNameFromPath(m.path),
fullName: m.path,
package: getPackageNameFromPath(m.path),
service: shortServiceName
})
// Buffers can be ignored, we're not going to find any services there.
if (Buffer.isBuffer(entry)) {
continue
}

queue.push(entry)

if (isService(entry)) {
const service = entry.service || entry
const methodNames = Object.keys(service)
const fullServiceName = getServiceNameFromPath(service[methodNames[0]].path)

if (services[fullServiceName]) {
continue
}

const shortServiceName = getShortServiceNameFromPath(service[methodNames[0]].path)

const methods = Object
.values(service)
.reduce((methods, method) => {
methods[method.path] = {
...getDesiredMethodProps(method),
name: getMethodNameFromPath(method.path),
fullName: method.path,
package: getPackageNameFromPath(method.path),
service: shortServiceName
}

return methods
}, {})

services[fullServiceName] = {
shortServiceName,
fullServiceName,
service,
methods
}
}
} else if (v && v.type && typeof v.type !== 'object') {
// Skip children
this.update(v, true)
}
})

visited.add(current)
}

return services
}
Expand Down Expand Up @@ -107,25 +145,17 @@ function getShortServiceNameFromPath (path) {
}

function isService (v) {
if (v && v.service) {
const vKeys = Object.keys(v.service)

return vKeys.length > 0 && v.service[vKeys[0]] && v.service[vKeys[0]].path &&
typeof v.service[vKeys[0]].path === 'string' && v.service[vKeys[0]].path[0] === '/'
} else if (v) {
const vKeys = Object.keys(v)

return vKeys.length > 0 && v[vKeys[0]] && v[vKeys[0]].path &&
typeof v[vKeys[0]].path === 'string' && v[vKeys[0]].path[0] === '/'
}
v = v.service || v
const vKeys = Object.keys(v)

return false
return vKeys.length > 0 && v[vKeys[0]] && v[vKeys[0]].path &&
typeof v[vKeys[0]].path === 'string' && v[vKeys[0]].path[0] === '/'
}

module.exports = {
getCallTypeFromCall,
getCallTypeFromDescriptor,
getServiceDefintions,
getServiceDefinitions,
getServiceNameFromPath,
getMethodNameFromPath,
getPackageNameFromPath,
Expand Down
Loading

0 comments on commit 3a95b51

Please sign in to comment.