Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
scratch-www
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
scratch-www
Commits
5de96c37
Commit
5de96c37
authored
Jul 06, 2020
by
picklesrus
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Exponentially back off the time between message polling instead of doing it every two minutes.
parent
b385288e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
110 additions
and
16 deletions
+110
-16
src/components/navigation/www/navigation.jsx
src/components/navigation/www/navigation.jsx
+24
-15
test/unit/components/navigation.test.jsx
test/unit/components/navigation.test.jsx
+86
-1
No files found.
src/components/navigation/www/navigation.jsx
View file @
5de96c37
...
@@ -27,7 +27,8 @@ class Navigation extends React.Component {
...
@@ -27,7 +27,8 @@ class Navigation extends React.Component {
super
(
props
);
super
(
props
);
bindAll
(
this
,
[
bindAll
(
this
,
[
'
getProfileUrl
'
,
'
getProfileUrl
'
,
'
handleSearchSubmit
'
'
handleSearchSubmit
'
,
'
setupMessagePolling
'
]);
]);
this
.
state
=
{
this
.
state
=
{
messageCountIntervalId
:
-
1
// javascript method interval id for getting messsage count.
messageCountIntervalId
:
-
1
// javascript method interval id for getting messsage count.
...
@@ -35,27 +36,18 @@ class Navigation extends React.Component {
...
@@ -35,27 +36,18 @@ class Navigation extends React.Component {
}
}
componentDidMount
()
{
componentDidMount
()
{
if
(
this
.
props
.
user
)
{
if
(
this
.
props
.
user
)
{
const
intervalId
=
setInterval
(()
=>
{
// Setup polling for messages to start in 2 minutes.
this
.
props
.
getMessageCount
(
this
.
props
.
user
.
username
);
setTimeout
(
this
.
setupMessagePolling
.
bind
(
this
,
2
),
2
*
60
*
1000
);
},
120000
);
// check for new messages every 2 mins.
this
.
setState
({
// eslint-disable-line react/no-did-mount-set-state
messageCountIntervalId
:
intervalId
});
}
}
}
}
componentDidUpdate
(
prevProps
)
{
componentDidUpdate
(
prevProps
)
{
if
(
prevProps
.
user
!==
this
.
props
.
user
)
{
if
(
prevProps
.
user
!==
this
.
props
.
user
)
{
this
.
props
.
handleCloseAccountNav
();
this
.
props
.
handleCloseAccountNav
();
if
(
this
.
props
.
user
)
{
if
(
this
.
props
.
user
)
{
const
intervalId
=
setInterval
(()
=>
{
setTimeout
(
this
.
setupMessagePolling
.
bind
(
this
,
2
),
2
*
60
*
1000
);
this
.
props
.
getMessageCount
(
this
.
props
.
user
.
username
);
},
120000
);
// check for new messages every 2 mins.
this
.
setState
({
// eslint-disable-line react/no-did-update-set-state
messageCountIntervalId
:
intervalId
});
}
else
{
}
else
{
// clear message count check, and set to default id.
// clear message count check, and set to default id.
clear
Interval
(
this
.
state
.
messageCountIntervalId
);
clear
Timeout
(
this
.
state
.
messageCountIntervalId
);
this
.
props
.
setMessageCount
(
0
);
this
.
props
.
setMessageCount
(
0
);
this
.
setState
({
// eslint-disable-line react/no-did-update-set-state
this
.
setState
({
// eslint-disable-line react/no-did-update-set-state
messageCountIntervalId
:
-
1
messageCountIntervalId
:
-
1
...
@@ -66,7 +58,7 @@ class Navigation extends React.Component {
...
@@ -66,7 +58,7 @@ class Navigation extends React.Component {
componentWillUnmount
()
{
componentWillUnmount
()
{
// clear message interval if it exists
// clear message interval if it exists
if
(
this
.
state
.
messageCountIntervalId
!==
-
1
)
{
if
(
this
.
state
.
messageCountIntervalId
!==
-
1
)
{
clear
Interval
(
this
.
state
.
messageCountIntervalId
);
clear
Timeout
(
this
.
state
.
messageCountIntervalId
);
this
.
props
.
setMessageCount
(
0
);
this
.
props
.
setMessageCount
(
0
);
this
.
setState
({
this
.
setState
({
messageCountIntervalId
:
-
1
messageCountIntervalId
:
-
1
...
@@ -77,6 +69,23 @@ class Navigation extends React.Component {
...
@@ -77,6 +69,23 @@ class Navigation extends React.Component {
if
(
!
this
.
props
.
user
)
return
;
if
(
!
this
.
props
.
user
)
return
;
return
`/users/
${
this
.
props
.
user
.
username
}
/`
;
return
`/users/
${
this
.
props
.
user
.
username
}
/`
;
}
}
setupMessagePolling
(
minutes
)
{
this
.
props
.
getMessageCount
(
this
.
props
.
user
.
username
);
// We only poll if it has been less than 30 minutes.
// Chances of someone actively using the page for that long without
// a navigation is low.
if
(
minutes
<
32
)
{
const
nextFetch
=
minutes
*
2
;
const
timeoutId
=
setTimeout
(()
=>
{
this
.
setupMessagePolling
(
nextFetch
);
},
nextFetch
*
60000
);
this
.
setState
({
// eslint-disable-line react/no-did-mount-set-state
messageCountIntervalId
:
timeoutId
});
}
}
handleSearchSubmit
(
formData
)
{
handleSearchSubmit
(
formData
)
{
let
targetUrl
=
'
/search/projects
'
;
let
targetUrl
=
'
/search/projects
'
;
if
(
formData
.
q
)
{
if
(
formData
.
q
)
{
...
...
test/unit/components/navigation.test.jsx
View file @
5de96c37
const
React
=
require
(
'
react
'
);
const
React
=
require
(
'
react
'
);
const
{
shallowWithIntl
}
=
require
(
'
../../helpers/intl-helpers.jsx
'
);
const
{
shallowWithIntl
,
mountWithIntl
}
=
require
(
'
../../helpers/intl-helpers.jsx
'
);
import
configureStore
from
'
redux-mock-store
'
;
import
configureStore
from
'
redux-mock-store
'
;
const
Navigation
=
require
(
'
../../../src/components/navigation/www/navigation.jsx
'
);
const
Navigation
=
require
(
'
../../../src/components/navigation/www/navigation.jsx
'
);
const
Registration
=
require
(
'
../../../src/components/registration/registration.jsx
'
);
const
Registration
=
require
(
'
../../../src/components/registration/registration.jsx
'
);
...
@@ -11,6 +11,7 @@ describe('Navigation', () => {
...
@@ -11,6 +11,7 @@ describe('Navigation', () => {
beforeEach
(()
=>
{
beforeEach
(()
=>
{
store
=
null
;
store
=
null
;
jest
.
useFakeTimers
();
});
});
const
getNavigationWrapper
=
props
=>
{
const
getNavigationWrapper
=
props
=>
{
...
@@ -103,4 +104,88 @@ describe('Navigation', () => {
...
@@ -103,4 +104,88 @@ describe('Navigation', () => {
navWrapper
.
find
(
'
a.registrationLink
'
).
simulate
(
'
click
'
,
{
preventDefault
()
{}});
navWrapper
.
find
(
'
a.registrationLink
'
).
simulate
(
'
click
'
,
{
preventDefault
()
{}});
expect
(
navInstance
.
props
.
handleClickRegistration
).
toHaveBeenCalled
();
expect
(
navInstance
.
props
.
handleClickRegistration
).
toHaveBeenCalled
();
});
});
test
(
'
Component sets up message polling when it mounts
'
,
()
=>
{
store
=
mockStore
({
navigation
:
{
registrationOpen
:
false
},
messageCount
:
{
messageCount
:
5
}
});
const
props
=
{
user
:
{
thumbnailUrl
:
'
scratch.mit.edu
'
,
username
:
'
auser
'
},
getMessageCount
:
jest
.
fn
()
};
const
intlWrapper
=
mountWithIntl
(
<
Navigation
{
...
props
}
/>,
{
context
:
{
store
},
childContextTypes
:
{
store
}
});
intlWrapper
.
children
().
find
(
'
Navigation
'
)
.
instance
();
const
twoMin
=
2
*
60
*
1000
;
expect
(
setTimeout
).
toHaveBeenLastCalledWith
(
expect
.
any
(
Function
),
twoMin
);
// Advance timers passed the intial two minutes.
jest
.
advanceTimersByTime
(
twoMin
+
1
);
expect
(
setTimeout
).
toHaveBeenLastCalledWith
(
expect
.
any
(
Function
),
twoMin
*
2
);
expect
(
props
.
getMessageCount
).
toHaveBeenCalled
();
});
test
(
'
SetupMessagePolling polls for messages 5 times
'
,
()
=>
{
store
=
mockStore
({
navigation
:
{
registrationOpen
:
false
},
messageCount
:
{
messageCount
:
5
}
});
const
props
=
{
user
:
{
thumbnailUrl
:
'
scratch.mit.edu
'
,
username
:
'
auser
'
},
getMessageCount
:
jest
.
fn
()
};
const
intlWrapper
=
mountWithIntl
(
<
Navigation
{
...
props
}
/>,
{
context
:
{
store
},
childContextTypes
:
{
store
}
});
const
navInstance
=
intlWrapper
.
children
().
find
(
'
Navigation
'
)
.
instance
();
// Clear the timers and mocks because componentDidMount
// has already called setupMessagePolling.
jest
.
clearAllTimers
();
jest
.
clearAllMocks
();
navInstance
.
setupMessagePolling
(
2
);
// Check that we set the timeout to backoff exponentially
let
minutes
=
2
*
60
*
1000
;
for
(
let
count
=
1
;
count
<
5
;
++
count
)
{
jest
.
advanceTimersByTime
(
minutes
+
1
);
expect
(
setTimeout
).
toHaveBeenLastCalledWith
(
expect
.
any
(
Function
),
minutes
*
2
);
expect
(
props
.
getMessageCount
).
toHaveBeenCalledTimes
(
count
);
minutes
=
minutes
*
2
;
}
// Exhaust all timers (there shouldn't be any left)
jest
.
runAllTimers
();
// We exponentially back off checking for messages, starting at 2 min
// and stop after 32 minutes so it should happen 5 times total.
expect
(
props
.
getMessageCount
).
toHaveBeenCalledTimes
(
5
);
// setTimeout happens 1 fewer since the original call to
// setupMessagePolling isn't counted here.
expect
(
setTimeout
).
toHaveBeenCalledTimes
(
4
);
});
});
});
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