Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
0958b019
Commit
0958b019
authored
Feb 19, 2016
by
Robert Knight
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2987 from hypothesis/randomize-websocket-reconnects
Randomize websocket reconnects
parents
d6aeb4b9
889fe9e0
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
75 additions
and
30 deletions
+75
-30
websocket-test.js
h/static/scripts/test/websocket-test.js
+18
-4
websocket.js
h/static/scripts/websocket.js
+57
-26
No files found.
h/static/scripts/test/websocket-test.js
View file @
0958b019
'use strict'
;
var
Socket
=
require
(
'../websocket'
);
var
Socket
=
require
(
'../websocket'
);
describe
(
'websocket wrapper'
,
function
()
{
describe
(
'websocket wrapper'
,
function
()
{
...
@@ -8,7 +10,7 @@ describe('websocket wrapper', function () {
...
@@ -8,7 +10,7 @@ describe('websocket wrapper', function () {
this
.
close
=
sinon
.
stub
();
this
.
close
=
sinon
.
stub
();
this
.
send
=
sinon
.
stub
();
this
.
send
=
sinon
.
stub
();
fakeSocket
=
this
;
fakeSocket
=
this
;
}
;
}
FakeWebSocket
.
OPEN
=
1
;
FakeWebSocket
.
OPEN
=
1
;
var
WebSocket
=
window
.
WebSocket
;
var
WebSocket
=
window
.
WebSocket
;
...
@@ -29,11 +31,23 @@ describe('websocket wrapper', function () {
...
@@ -29,11 +31,23 @@ describe('websocket wrapper', function () {
});
});
it
(
'should reconnect after an abnormal disconnection'
,
function
()
{
it
(
'should reconnect after an abnormal disconnection'
,
function
()
{
var
socket
=
new
Socket
(
'ws://test:1234'
);
new
Socket
(
'ws://test:1234'
);
assert
.
ok
(
fakeSocket
);
assert
.
ok
(
fakeSocket
);
var
initialSocket
=
fakeSocket
;
var
initialSocket
=
fakeSocket
;
fakeSocket
.
onopen
({});
fakeSocket
.
onclose
({
code
:
1006
});
clock
.
tick
(
2000
);
assert
.
ok
(
fakeSocket
);
assert
.
notEqual
(
fakeSocket
,
initialSocket
);
});
it
(
'should reconnect if initial connection fails'
,
function
()
{
new
Socket
(
'ws://test:1234'
);
assert
.
ok
(
fakeSocket
);
var
initialSocket
=
fakeSocket
;
fakeSocket
.
onopen
({});
fakeSocket
.
onclose
({
code
:
1006
});
fakeSocket
.
onclose
({
code
:
1006
});
clock
.
tick
(
1
000
);
clock
.
tick
(
4
000
);
assert
.
ok
(
fakeSocket
);
assert
.
ok
(
fakeSocket
);
assert
.
notEqual
(
fakeSocket
,
initialSocket
);
assert
.
notEqual
(
fakeSocket
,
initialSocket
);
});
});
...
@@ -57,7 +71,7 @@ describe('websocket wrapper', function () {
...
@@ -57,7 +71,7 @@ describe('websocket wrapper', function () {
socket
.
close
();
socket
.
close
();
assert
.
called
(
fakeSocket
.
close
);
assert
.
called
(
fakeSocket
.
close
);
var
initialSocket
=
fakeSocket
;
var
initialSocket
=
fakeSocket
;
clock
.
tick
(
1
000
);
clock
.
tick
(
2
000
);
assert
.
equal
(
fakeSocket
,
initialSocket
);
assert
.
equal
(
fakeSocket
,
initialSocket
);
});
});
...
...
h/static/scripts/websocket.js
View file @
0958b019
...
@@ -7,6 +7,9 @@ var inherits = require('inherits');
...
@@ -7,6 +7,9 @@ var inherits = require('inherits');
// see https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
// see https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
var
CLOSE_NORMAL
=
1000
;
var
CLOSE_NORMAL
=
1000
;
// Minimum delay, in ms, before reconnecting after an abnormal connection close.
var
RECONNECT_MIN_DELAY
=
1000
;
/**
/**
* Socket is a minimal wrapper around WebSocket which provides:
* Socket is a minimal wrapper around WebSocket which provides:
*
*
...
@@ -25,6 +28,9 @@ function Socket(url) {
...
@@ -25,6 +28,9 @@ function Socket(url) {
// the current WebSocket instance
// the current WebSocket instance
var
socket
;
var
socket
;
// a pending operation to connect a WebSocket
var
operation
;
function
sendMessages
()
{
function
sendMessages
()
{
while
(
messageQueue
.
length
>
0
)
{
while
(
messageQueue
.
length
>
0
)
{
var
messageString
=
JSON
.
stringify
(
messageQueue
.
shift
());
var
messageString
=
JSON
.
stringify
(
messageQueue
.
shift
());
...
@@ -32,44 +38,70 @@ function Socket(url) {
...
@@ -32,44 +38,70 @@ function Socket(url) {
}
}
}
}
function
reconnect
()
{
// Connect the websocket immediately. If a connection attempt is already in
var
didConnect
=
false
;
// progress, do nothing.
var
connectOperation
=
retry
.
operation
();
function
connect
()
{
connectOperation
.
attempt
(
function
(
currentAttempt
)
{
if
(
operation
)
{
return
;
}
operation
=
retry
.
operation
({
minTimeout
:
RECONNECT_MIN_DELAY
*
2
,
// Don't retry forever -- fail permanently after 10 retries
retries
:
10
,
// Randomize retry times to minimise the thundering herd effect
randomize
:
true
});
operation
.
attempt
(
function
()
{
socket
=
new
WebSocket
(
url
);
socket
=
new
WebSocket
(
url
);
socket
.
onopen
=
function
(
event
)
{
socket
.
onopen
=
function
(
event
)
{
// signal successful connection
onOpen
();
connectOperation
.
retry
();
didConnect
=
true
;
sendMessages
();
self
.
emit
(
'open'
,
event
);
self
.
emit
(
'open'
,
event
);
};
};
socket
.
onclose
=
function
(
event
)
{
socket
.
onclose
=
function
(
event
)
{
if
(
event
.
code
!==
CLOSE_NORMAL
)
{
if
(
event
.
code
===
CLOSE_NORMAL
)
{
if
(
didConnect
)
{
console
.
warn
(
'The WebSocket connection closed abnormally '
+
'(code: %d, reason: %s). Reconnecting automatically.'
,
event
.
code
,
event
.
reason
);
reconnect
();
}
else
{
console
.
warn
(
'Retrying connection (attempt %d)'
,
currentAttempt
);
connectOperation
.
retry
(
new
Error
(
event
.
reason
));
}
}
self
.
emit
(
'close'
,
event
);
self
.
emit
(
'close'
,
event
);
return
;
}
var
err
=
new
Error
(
'WebSocket closed abnormally, code: '
+
event
.
code
);
console
.
warn
(
err
);
onAbnormalClose
(
err
);
};
};
socket
.
onerror
=
function
(
event
)
{
socket
.
onerror
=
function
(
event
)
{
self
.
emit
(
'error'
,
event
);
self
.
emit
(
'error'
,
event
);
};
};
socket
.
onmessage
=
function
(
event
)
{
socket
.
onmessage
=
function
(
event
)
{
self
.
emit
(
'message'
,
event
);
self
.
emit
(
'message'
,
event
);
};
};
});
});
};
}
// onOpen is called when a websocket connection is successfully established.
function
onOpen
()
{
operation
=
null
;
sendMessages
();
}
// onAbnormalClose is called when a websocket connection closes abnormally.
// This may be the result of a failure to connect, or an abnormal close after
// a previous successful connection.
function
onAbnormalClose
(
error
)
{
// If we're already in a reconnection loop, trigger a retry...
if
(
operation
)
{
if
(
!
operation
.
retry
(
error
))
{
console
.
error
(
'reached max retries attempting to reconnect websocket'
);
}
return
;
}
// ...otherwise reconnect the websocket after a short delay.
var
delay
=
RECONNECT_MIN_DELAY
;
delay
+=
Math
.
floor
(
Math
.
random
()
*
delay
);
operation
=
setTimeout
(
function
()
{
operation
=
null
;
connect
();
},
delay
);
}
/** Close the underlying WebSocket connection */
/** Close the underlying WebSocket connection */
this
.
close
=
function
()
{
this
.
close
=
function
()
{
...
@@ -92,8 +124,7 @@ function Socket(url) {
...
@@ -92,8 +124,7 @@ function Socket(url) {
return
socket
.
readyState
===
WebSocket
.
OPEN
;
return
socket
.
readyState
===
WebSocket
.
OPEN
;
};
};
// establish the initial connection
connect
();
reconnect
();
}
}
inherits
(
Socket
,
EventEmitter
);
inherits
(
Socket
,
EventEmitter
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment