Add support for outgoing heartbeats - #72
Conversation
- add observer based heartbeat emitter, which must be added to the connection if outgoing heartbeats are wanted - allow to use heartbeats when connection is reopened by server - fix older test cases to be more precise and fix preconditions
| } | ||
|
|
||
| /** | ||
| * Set the desired heartbeat for the connection. |
There was a problem hiding this comment.
we should spent a small sentence why one would want to use a heartbeat (which problem it solves conceptionally)
| public function receivedFrame(Frame $frame); | ||
|
|
||
| /** | ||
| * Indicates that a frame has been transmitted. |
There was a problem hiding this comment.
the word transmit does not imply a direction, does it?
received fits as it describes a incoming frame, but transmitted isnt a good fit IMO.
maybe sentFrame or somthing?
| * Adds new observers to the collection. | ||
| * | ||
| * @param ConnectionObserver $observer | ||
| * @return ConnectionObserverCollection |
There was a problem hiding this comment.
$this (same in other spots of this class)
There was a problem hiding this comment.
I used to replace $this with the actual return type since some time now. I also see that at symfony code - I would just like to change it to something like @return ConnectionObserverCollection this collection - what do you think about that?
| * | ||
| * @return ConnectionObserver[] | ||
| */ | ||
| public function getObserver() |
| */ | ||
| public function receivedFrame(Frame $frame) | ||
| { | ||
| if ($frame->getCommand() === 'CONNECTED') { |
There was a problem hiding this comment.
should we have constants for this magic strings?
| */ | ||
| private function getHeartbeats(Frame $frame) | ||
| { | ||
| $beats = $frame['heart-beat']; |
There was a problem hiding this comment.
The ArrayAccess implementation of Frame will return null if the header is not available. That simplified some work with the headers.
| if (!@fwrite($this->connection, $data, strlen($data))) { | ||
| throw new ConnectionException('Was not possible to write frame!', $this->activeHost); | ||
| } | ||
| $this->getObserver()->transmittedFrame($stompFrame); |
There was a problem hiding this comment.
we shouldnt use the getter inside off this class... this is a very hot path of our lib .. just use $this->observer instead.
I have the same feeling for isConnected(), hasDataToRead() etc. within this class, but this shouldn't be changed with this PR. I guess we can speedup the client a lot when we prevent this calls and just inline the code (the methods should still be preserved for public consumption and BC)
There was a problem hiding this comment.
That's right we should check that in our next release.
|
Great Job, just a few minor nits/questions! |
|
@staabm - Thank you for the review 👍 I'll apply the notes within a few days. |
|
Also updated the examples stomp-php/stomp-php-examples@fb02c79. If everything is fine we can squeeze and merge this. |
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Stomp\Network\Observer\Heartbeat; |
There was a problem hiding this comment.
This is a single class Namspace.. should we instead strip heartbeat from the NS and name the class HeartbeatEmitter ?
There was a problem hiding this comment.
Yes, when I added it I thought about the Monitor but there will be never more than two, so it's fine to Prefix them.
| * within an interval - to indicate that the connection is still stable. If client and server agree on a beat and | ||
| * the interval passes without any data activity / beats the connection will be considered as broken and closed. | ||
| * | ||
| * If you define a heartbeat, you must assure that your application will send data within the interval. |
There was a problem hiding this comment.
hmm isn't it exactly the opposite? in case you use heartbeats you dont need to send data in certain intervalls as the client will automatically sent a hearbeat to keep the connection alive..?
There was a problem hiding this comment.
jein - without a heartbeat declaration you can send data whenever you want, you could even add some minutes of sleep between the communication.
With heartbeats enabled you must do something within the interval.
The emitter is not automatically attached to the connection. Maybe this description is not yet good enough yet. But it's not that easy, hm...
There was a problem hiding this comment.
hm does it make sense to enable hearbeats but dont add the emitter?
There was a problem hiding this comment.
I think so, for those who don't like to add the overhead and expect to send data within the interval.
| * | ||
| * @return void | ||
| */ | ||
| private function notifyBeat() |
| } | ||
|
|
||
| /** | ||
| * Returns the heart beat header. |
| if ($frame->getCommand() === Emitter::FRAME_CLIENT_CONNECT) { | ||
| $beats = $this->getHeartbeats($frame); | ||
| $this->intervalClient = $beats[0]; | ||
| $this->notifyBeat(); |
There was a problem hiding this comment.
do we need enabled=true in this IF?
There was a problem hiding this comment.
No, it should be possible to support the RabbitMQ "Implicit Connect" (https://www.rabbitmq.com/stomp.html) this works without a CONNECT frame - so the enabled flag is here to query the state, but not to control it. (see testEmitterActivatedIfServerRequestsBeatsAndNoConnectFrameWasSend)
| * | ||
| * @param float $intervalUsage | ||
| */ | ||
| public function setIntervalUsage($intervalUsage) |
There was a problem hiding this comment.
as this value should be set before the emitter gets active, should it be a constructor arg instead?
| { | ||
| if ($this->isConnected()) { | ||
| return (!@fwrite($this->connection, "\n", 1) == true); | ||
| } |
There was a problem hiding this comment.
Intentionally not a strict comparison?
There was a problem hiding this comment.
It's easy to see that this might return nothing good...
Good reason to wait until Tuesday before opening a PR the next time ;)
In #60 we see that heartbeats support might help to avoid broken connections or at least they can reduce the lack from error to notification.
This only includes support for outgoing beats, incoming beats are not yet included. I could imagine to use the same observer infrastructure to offer support for incoming beat detection.