简体   繁体   中英

Modifying Pubnub presence heartbeat for Python

According to the presence documentation, Pubnub will fire the Timeout presence event after 5 minutes of not receiving a heartbeat. I need to modify this value but I cannot find a way of doing this with the Python SDK. Here is a link to the Pubnub docs showing how to do it with JavaScript: http://www.pubnub.com/docs/web-javascript/presence#optimizing_timeout_events

Does anyone know how to achieve this using the python SDK?

Thanks a lot.

edit: My clients are not javascript clients. They are python console applications.

PubNub Python SDK Presence

Because Python is rarely used as a client , the PubNub Python SDK 's presence API is not as robustly implemented as the traditional client SDKs (JavaScript, etc.). So there is no heartbeat parameter in the Pubnbub intitializer nor is there a setter or attribute for this so you are forced to stick with the default 5 minute heartbeat setting.

However, with thePubNub JavaScript SDK , when you init PUBNUB with a custom heartbeat (60 seconds for example), the heartbeat key/value is just passed along as a query param in the REST URL:

http://pubsub.pubnub.com/subscribe/demo/my_channel/0/14411482999795083?uuid=12345&pnsdk=PubNub-JS-Web%2F3.7.14&heartbeat=60

So if you really wanted to, you could just subscribe using REST calls and pass the heartbeat in that way.

What I forgot to mention when I first posted this answer is that your client is responsible for pinging the PubNub server at least once every 60 seconds, preferably on a 30 second interval this the 60 second heartbeat window that the server is configured for this client.

With the PubNub SDK, this is done in a separate thread over the same connection (sort of - at least in a way that the server knows that it is the same client that set the heartbeat).

That said, we are getting into a less trivial solution using REST and so why even use the SDK. It would be easier for us to update the Python SDK than for you to do all the dirty work. We will do just that but not in the short term but hopefully with the next minor release of the Python SDK.

Based on our off-SO conversation, you just want to shorten the window of time that a client will appear to be online when in fact the client is not connected and was unable to explicitly unsubscribe before the connection was closed (closed the terminal instead of "logging off" using your app's UI or command line).

What you can do is implement a ping/ack handshake protocol. This is very high level so there may be some finer points that need to be filled in but it should provide the general concept.

  • Before one client (sender) engages in communication with another (receiver), just send a ping message to the other client on the client's private channel (every client will subscribe to a channel unique to that client: for example, private_client001, private_client002, etc.).
  • The receiving client will auto-ack back on the sender's unique channel (which will be part of the ping msg payload)
  • If the sender of the ping doesn't get an ack msg back within a second (or whatever time tolerance works for you) then assume the receiver is not online.
  • When the receiver comes back online, you get missed messages, and any pings that are less than 5 minutes old, you can ack back and see if the sender still wants to engage.

This is a common issue for many use cases (especially chat) because there is always that window of time (the heartbeat window) that a client could really be offline but appear to be online because they did not leave in proper, predictable fashion that would have produced an explicit unsubscribe resulting in a leave event. So implementing this sort of handshake pre-connect protocol is a good practice.

Heartbeat can be monkey-patched into the Pubnub class with something like this:

from pubnub import Pubnub

class PubnubHeartbeat(Pubnub):
    def __init__(self, heartbeat=300, **kwargs):
        self.heartbeat = heartbeat
        super(PubnubHeartbeat, self).__init__(**kwargs)

    def getUrl(self, request):
        if "subscribe" in request['urlcomponents'][:2]:
            if "urlparams" not in request:
                request['urlparams'] = {}
            request['urlparams']['heartbeat'] = self.heartbeat

        return super(PubnubHeartbeat, self).getUrl(request)


p = PubnubHeartbeat(
    subscribe_key="demo",
    publish_key="demo",
    heartbeat=60
)

def recv(msg):
    print msg

p.subscribe(channels="heartbeat_test", callback=recv)

This isn't recommended for long-term production code (unless maybe if you are pinning your Pubnub dependency with pubnub==3.7.3 during install). The example subclass uses an undocumented method to inject the heartbeat URL parameter. (See Craig Conover's answer for a description of what that does).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM