-
Notifications
You must be signed in to change notification settings - Fork 364
Run cypher queries on web workers #591
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
oskarhane
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work!
I added a few questions for things I don't understand.
package.json
Outdated
| "webpack-dashboard": "^0.4.0", | ||
| "webpack-dev-server": "^2.4.2" | ||
| "webpack-dev-server": "^2.4.2", | ||
| "worker-loader": "^0.8.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation
src/shared/services/bolt/bolt.js
Outdated
| if (enableWebWorkers && window.Worker) { | ||
| const id = requestId || v4() | ||
| /* eslint-disable import/no-webpack-loader-syntax */ | ||
| const BoltWorkerModule = require('worker-loader!./boltWorker.js') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not import as a regular module at the top of the file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/shared/services/bolt/bolt.js
Outdated
| let connectionProperties = null | ||
| let boltWorkerRegister = {} | ||
| let cancellationRegister = {} | ||
| let enableWebWorkers = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should start off by have this as a "experimental" setting in the config pane?
wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return rows.map((row) => row.map((entry) => (entry && entry.properties) ? entry.properties : entry)) | ||
| } | ||
|
|
||
| export const applyGraphTypes = (item) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see this function tested, so we don't introduce regressions if we need to make changes in it in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely. Done!
| } | ||
| } | ||
|
|
||
| self.addEventListener('message', onmessage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is self?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is needed by worker loader on the worker script
|
|
||
| export const applyGraphTypes = (item) => { | ||
| if (Array.isArray(item)) { | ||
| return item.map(arrayItem => applyGraphTypes(arrayItem)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor thing, but it's easier to read if you do this item.map(applyGraphTypes).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| } else if (item.hasOwnProperty('segments') && item.hasOwnProperty('start') && item.hasOwnProperty('end')) { | ||
| const start = applyGraphTypes(item.start) | ||
| const end = applyGraphTypes(item.end) | ||
| const segments = item.segments.map(segment => applyGraphTypes(segment)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above: item.map(applyGraphTypes).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| test('should apply node type', () => { | ||
| const rawNode = { | ||
| labels: ['Test'], | ||
| properties: [], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add some properties of different types (integers, string, array, null, object) to make sure they come along.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| return new neo4j.types.Relationship(neo4j.int(item.identity), neo4j.int(item.start), neo4j.int(item.end), item.type, applyGraphTypes(item.properties)) | ||
| } else if (item.hasOwnProperty('low') && item.hasOwnProperty('high') && typeof item.low === 'number' && typeof item.high === 'number') { | ||
| return neo4j.int(item) | ||
| } else if (typeof item === 'object') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null is of type object so this will probably throw.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
definitely! done.
| expect(typedRelationships[1].end instanceof neo4j.Integer).toEqual(true) | ||
| }) | ||
|
|
||
| test('should apply to custom object properties', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test tests nodes again, not regular js objects. Please add tests for primitives as well, like bool, null, string, float etc.
3e48d4c to
90a069f
Compare
90a069f to
b4202cc
Compare
|
I just rebased this over master and things are looking good. There's a jumpy behaviour going from spinner -> result that needs to be addressed before I want to merge this. |
1eda6b6 to
166034e
Compare
|
I've now addressed the "double frame insert animation" I was seeing. I'm approving this to be merged. Anyone else want to have a last check before merging @pe4cey @irfannuri @akollegger? I'm merging after lunch tomorrow (CEST) unless someone tells me not to 🐎 |
If not the web server serving the Neo4j Browser have to be online to be able to run queries.
Set web worker file as: `/* eslint-env serviceworker */` instead.
4275a13 to
04798c4
Compare

This PR enables running cypher queries on separate web workers (when available) so that web browser does not freeze and remains responsive. A brief list of facts about the implementation is listed below:
routedWriteTransactionis called), a new web worker is created and the request is passed to that workerWith the use of web workers, it is possible to run multiple long running queries and still use the browser as seen in the attached screen shot. This was not possible, especially when the running query immediately started streaming results, which caused bolt driver to fully occupy cpu thus making UI non-responsive.
To disable web workers, for a limited time you can do so by
:config useCypherThread: false.This option will probably be removed in the future.
changelog: Use separate thread for running cypher queries