-
Notifications
You must be signed in to change notification settings - Fork 151
Connection Hint: supporting connection.recv_timeout_seconds #761
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
Changes from 9 commits
7296e81
c0945de
fe5d296
e2b69d1
d1bd6fc
89f5d8b
ef2d95a
23569ac
a1e82f6
c426699
b10795c
3f9ba3d
a4b29c5
d77a6e4
ad7ec10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ | |
*/ | ||
|
||
import { Chunker, Dechunker, ChannelConfig, Channel } from '../channel' | ||
import { newError, error, json, internal } from 'neo4j-driver-core' | ||
import { newError, error, json, internal, toNumber } from 'neo4j-driver-core' | ||
import Connection from './connection' | ||
import Bolt from '../bolt' | ||
|
||
|
@@ -198,6 +198,25 @@ export default class ChannelConnection extends Connection { | |
if (!this.databaseId) { | ||
this.databaseId = dbConnectionId | ||
} | ||
|
||
if (metadata.hints) { | ||
const receiveTimeoutRaw = | ||
metadata.hints['connection.recv_timeout_seconds'] | ||
if ( | ||
receiveTimeoutRaw !== null && | ||
receiveTimeoutRaw !== undefined | ||
) { | ||
const receiveTimeoutInSeconds = toNumber(receiveTimeoutRaw) | ||
if (receiveTimeoutInSeconds > 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if even feasible in JS's limited number type, but we also don't expect floats from the server. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will create tests with float number to limit this option. One question, should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know how the JS drivers handles numbers internally. But the server is expected to sent an Integer (strongly typed through packstream). It might well be, however, that at this point in the code, the type information is already lost. In that case, I'd say 3.0 is also ok. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At that point, I already lost this information. Since 3 is the same as 3.0 for JS. So, I'm verifying if it's a Integer using the JS Number definition of integer. |
||
this._ch.setupReceiveTimeout(receiveTimeoutInSeconds * 1000) | ||
} else { | ||
this._log.info( | ||
`Server located at ${this._address} supplied an invalid connection receive timeout value (${receiveTimeoutInSeconds}). ` + | ||
'Please, verify the server configuration and status because this can a symptom of a bigger issue.' | ||
bigmontz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
} | ||
} | ||
} | ||
} | ||
resolve(self) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/** | ||
* Copyright (c) "Neo4j" | ||
* Neo4j Sweden AB [http://neo4j.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
import NodeChannel from '../../../src/channel/node/node-channel' | ||
import ChannelConfig from '../../../src/channel/channel-config' | ||
import { error, internal, newError } from 'neo4j-driver-core' | ||
|
||
const { | ||
serverAddress: { ServerAddress } | ||
} = internal | ||
|
||
const { SERVICE_UNAVAILABLE } = error | ||
|
||
describe('NodeChannel', () => { | ||
it('should resolve close if websocket is already closed', () => { | ||
const address = ServerAddress.fromUrl('bolt://localhost:9999') | ||
const channelConfig = new ChannelConfig(address, {}, SERVICE_UNAVAILABLE) | ||
const channel = new NodeChannel(channelConfig) | ||
|
||
// Modify the connection to be closed | ||
channel._open = false | ||
|
||
return expect(channel.close()).resolves.not.toThrow() | ||
}) | ||
|
||
it('should resolve close when websocket is connected', () => { | ||
const channel = createMockedChannel(true) | ||
|
||
return expect(channel.close()).resolves.not.toThrow() | ||
}) | ||
|
||
describe('.setupReceiveTimeout()', () => { | ||
it('should call socket.setTimeout(receiveTimeout)', () => { | ||
const receiveTimeout = 42 | ||
const channel = createMockedChannel(true) | ||
|
||
channel.setupReceiveTimeout(receiveTimeout) | ||
|
||
expect(channel._conn.getCalls().setTimeout[1]).toEqual([receiveTimeout]) | ||
}) | ||
|
||
it('should unsubscribe to the on connect and on timeout created on the create socket', () => { | ||
const receiveTimeout = 42 | ||
const channel = createMockedChannel(true) | ||
|
||
channel.setupReceiveTimeout(receiveTimeout) | ||
|
||
expect(channel._conn.getCalls().on.slice(0, 2)).toEqual( | ||
channel._conn.getCalls().off | ||
) | ||
}) | ||
|
||
it('should destroy the connection when time out', () => { | ||
const receiveTimeout = 42 | ||
const channel = createMockedChannel(true) | ||
|
||
channel.setupReceiveTimeout(receiveTimeout) | ||
|
||
const [event, listener] = channel._conn.getCalls().on[2] | ||
expect(event).toEqual('timeout') | ||
listener() | ||
|
||
expect(channel._conn.getCalls().destroy).toEqual([ | ||
[ | ||
newError( | ||
"Connection lost. Server didn't respond in 42ms", | ||
SERVICE_UNAVAILABLE | ||
) | ||
] | ||
]) | ||
}) | ||
|
||
it('should not unsubscribe to the any on connect or on timeout if connectionTimeout is not set', () => { | ||
bigmontz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const receiveTimeout = 42 | ||
const channel = createMockedChannel(true, { connectionTimeout: 0 }) | ||
|
||
channel.setupReceiveTimeout(receiveTimeout) | ||
|
||
expect(channel._conn.getCalls().off).toEqual([]) | ||
}) | ||
}) | ||
}) | ||
|
||
function createMockedChannel (connected, config = {}) { | ||
let endCallback = null | ||
const address = ServerAddress.fromUrl('bolt://localhost:9999') | ||
const channelConfig = new ChannelConfig(address, config, SERVICE_UNAVAILABLE) | ||
const socketFactory = () => { | ||
const on = [] | ||
const off = [] | ||
const setTimeout = [] | ||
const destroy = [] | ||
return { | ||
destroyed: false, | ||
destroy: () => { | ||
destroy.push([...arguments]) | ||
}, | ||
end: () => { | ||
channel._open = false | ||
endCallback() | ||
}, | ||
removeListener: () => {}, | ||
on: (key, cb) => { | ||
on.push([...arguments]) | ||
if (key === 'end') { | ||
endCallback = cb | ||
} | ||
}, | ||
off: () => { | ||
off.push([...arguments]) | ||
}, | ||
setTimeout: () => { | ||
setTimeout.push([...arguments]) | ||
}, | ||
getCalls: () => { | ||
return { on, off, setTimeout, destroy } | ||
} | ||
} | ||
} | ||
const channel = new NodeChannel(channelConfig, socketFactory) | ||
channel._open = connected | ||
return channel | ||
} |
Uh oh!
There was an error while loading. Please reload this page.