Give the server more time to send a heartbeat to make sure one missed heartbeat does not close the connection

This commit is contained in:
Thijs Blom 2019-01-15 13:12:57 +01:00
parent 3e5cbd0c5d
commit a3c68009e7
1 changed files with 15 additions and 12 deletions

View File

@ -192,11 +192,12 @@ private:
ev_tstamp _expire; ev_tstamp _expire;
/** /**
* Interval between heartbeats (we should send every interval / 2 a new heartbeat) * Timeout after which the connection is no longer considered alive.
* A heartbeat must be sent every _timeout / 2 seconds.
* Value zero means heartbeats are disabled, or not yet negotiated. * Value zero means heartbeats are disabled, or not yet negotiated.
* @var uint16_t * @var uint16_t
*/ */
uint16_t _interval = 0; uint16_t _timeout = 0;
/** /**
* Callback method that is called by libev when the timer expires * Callback method that is called by libev when the timer expires
@ -221,8 +222,8 @@ private:
// get the current time // get the current time
ev_tstamp now = ev_now(_loop); ev_tstamp now = ev_now(_loop);
// if the onNegotiate method was not yet called, and no heartbeat interval was negotiated // if the onNegotiate method was not yet called, and no heartbeat timeout was negotiated
if (_interval == 0) if (_timeout == 0)
{ {
// there is a theoretical scenario in which the onNegotiate() method // there is a theoretical scenario in which the onNegotiate() method
// was overridden, so that the connection-timeout-timer expires, but // was overridden, so that the connection-timeout-timer expires, but
@ -245,7 +246,7 @@ private:
_connection->heartbeat(); _connection->heartbeat();
// remember when we should send out the next one // remember when we should send out the next one
_next += std::max(_interval / 2, 1); _next += std::max(_timeout / 2, 1);
} }
// reset the timer to trigger again later // reset the timer to trigger again later
@ -264,7 +265,9 @@ private:
virtual void onActive(int fd, int events) override virtual void onActive(int fd, int events) override
{ {
// if the server is readable, we have some extra time before it expires // if the server is readable, we have some extra time before it expires
if (_interval != 0 && (events & EV_READ)) _expire = ev_now(_loop) + _interval; // the expire time is set to 1.5 * _timeout to close the connection when the
// third heartbeat is about to be sent
if (_timeout != 0 && (events & EV_READ)) _expire = ev_now(_loop) + _timeout * 1.5;
// pass on to the connection // pass on to the connection
_connection->process(fd, events); _connection->process(fd, events);
@ -283,7 +286,7 @@ private:
_loop(loop), _loop(loop),
_next(0.0), _next(0.0),
_expire(ev_now(loop) + timeout), _expire(ev_now(loop) + timeout),
_interval(0) _timeout(0)
{ {
// store the object in the data "void*" // store the object in the data "void*"
_timer.data = this; _timer.data = this;
@ -323,19 +326,19 @@ private:
* @param interval the heartbeat interval proposed by the server * @param interval the heartbeat interval proposed by the server
* @return uint16_t the heartbeat interval that we accepted * @return uint16_t the heartbeat interval that we accepted
*/ */
uint16_t start(uint16_t interval) uint16_t start(uint16_t timeout)
{ {
// we now know for sure that the connection was set up // we now know for sure that the connection was set up
_interval = interval; _timeout = timeout;
// if heartbeats are disabled we do not have to set it // if heartbeats are disabled we do not have to set it
if (_interval == 0) return 0; if (_timeout == 0) return 0;
// calculate current time // calculate current time
auto now = ev_now(_loop); auto now = ev_now(_loop);
// we also know when the next heartbeat should be sent // we also know when the next heartbeat should be sent
_next = now + std::max(1, _interval / 2); _next = now + std::max(_timeout / 2, 1);
// find the earliest thing that expires // find the earliest thing that expires
// @todo does this work? // @todo does this work?
@ -345,7 +348,7 @@ private:
ev_timer_again(_loop, &_timer); ev_timer_again(_loop, &_timer);
// expose the accepted interval // expose the accepted interval
return _interval; return _timeout;
} }
/** /**