question

Upvote
Accepted
46 1 1 4

Connection to remote host is lost when using Eikon Messenger Bot API (WebSocket)

Hello,

I need your help. I am using the python demo script for the Eikon Messenger API to listen in a chatroom. Unfortunately, the connection to the remote host is lost after a certain time every time. Is it the WebSocket service or threading in Python or am I getting kicked out by Refinitiv?

Thanks.

websocketsconnectionconnection-errormessenger-bot-api
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

<AHS>

I am contacting the client via an email to get more information.

@Cemil Yigit

Hi,

Thank you for your participation in the forum.

Are any of the replies below satisfactory in resolving your query?

If yes please click the 'Accept' text next to the most appropriate reply. This will guide all community members who have a similar question.

Otherwise please post again offering further insight into your question.

Thanks,

AHS

Please be informed that a reply has been verified as correct in answering the question, and has been marked as such.

Thanks,


AHS

Upvotes
Accepted
24.6k 54 17 14

All,

After investigating this disconnection issue for a while, @Cemil Yigit found that the proxy needs some kind of heartbeat messages or activities every certain minute to keep a WebSocket connection active.

The workaround is sending a ping-pong message with the WebSocket connection as follows:

def on_ping(_, message):
    print("Got a ping! A pong reply has already been automatically sent.")
def on_pong(_, message):
    print("Got a pong! No need to respond")

web_socket_app = websocket.WebSocketApp(
        ws_url,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close,
        on_ping=on_ping,
        on_pong=on_pong,
        subprotocols=['messenger-json'])
wst = threading.Thread(target=web_socket_app.run_forever, kwargs={"sslopt": {"check_hostname": False}, "ping_interval": 60, "ping_timeout": 10, "ping_payload": "2"})

The code also needs to handle reconnection logic (as the example application aims for demonstrating the API workflow only, so it is not cover all use cases).


After ping-pong and reconnection logic are applied to the application, the application works fine.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
24.6k 54 17 14

Hello @Cemil Yigit

Does the WebSocket connection disconnect every 5 minutes? If so, I highly recommend you re-test with the latest version (June 2022 - master branch) of the https://github.com/Refinitiv-API-Samples/Example.MessengerChatBot.Python example.

Please also share the log file too (please remove your credentials before sharing!).

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
46 1 1 4

Yes, it seems, that after 5 Minutes it disconnects. I'll check your link.


icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
46 1 1 4

Hello @wasin.w

Thanks for your post. I downloaded the chatbot_demo_ws.py file from git and tried it. Unfortunately, it now lost the connection after 2 minutes. Here ist some output:


Connecting to WebSocket wss://api.collab.refinitiv.com/services/nt/api/messenger/v1/stream ...

2022-09-06 11:10:02: DEBUG:websocket :Connecting proxy...

2022-09-06 11:10:02: INFO:root :Receive: onopen event. WebSocket Connection is established

2022-09-06 11:10:02: INFO:root :Sent: {.......}

2022-09-06 11:12:40: ERROR:root :Error: Connection to remote host was lost.

2022-09-06 11:12:40: ERROR:websocket :error from callback <function on_close at 0x00000273DA7E5DC0>: on_close() takes 1 positional argument but 3 were given

2022-09-06 11:12:40: ERROR:root :Error: on_close() takes 1 positional argument but 3 were given

Refresh Token

2022-09-06 11:14:02: DEBUG:urllib3.connectionpool :Starting new HTTPS connection (1): api.refinitiv.com:443

2022-09-06 11:14:03: DEBUG:urllib3.connectionpool :https://api.refinitiv.com:443 "POST /auth/oauth2/v1/token HTTP/1.1" 200 None

2022-09-06 11:14:03: ERROR:root :send_ws_connect_request exception: Connection is already closed.

2022-09-06 11:14:03: INFO:root :Sent: {.......}

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
46 1 1 4

A log file was not created.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
46 1 1 4

It's funny, when changing 60 to 180 in the while loop, it seems that is works.


icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvote
24.6k 54 17 14

Hello @Cemil Yigit

Sorry for my mistake, the demo application does not generate a log file. Can you save entire log messages (please removed your credentials) and share a text file in this post?

I am trying to replicate the issue with the chatbot_demo_ws.py example in my environment (Python 3.9, libraries versions are the same as in the ws-requirements.txt file).

I did not encounter any disconnection yet (Note: I am connecting with my public internet, not the office environment network).

According to the following logs, are you connecting to the Messenger Bot WebSocket server through any firewall or proxy?

2022-09-06 11:10:02: DEBUG:websocket :Connecting proxy...
2022-09-06 11:10:02: INFO:root :Receive: onopen event. WebSocket Connection is established
2022-09-06 11:10:02: INFO:root :Sent: {.......}
2022-09-06 11:12:40: ERROR:root :Error: Connection to remote host was lost.

If so, does your network have any policy that cuts a long connection like WebSocket?

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
46 1 1 4

Hello @wasin.w

Thanks for your support so far.

The hint with the proxy is a good one. I will check it and let you know if it's on my side. In the meantime I adjusted

time.sleep(int(expire_time) - 240)

For the moment, it works fine with 240. If it's not working, I'll let you know and push my code here.

Best, Cemil

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
46 1 1 4

Hello @wasin.w

Unfortunately, the connection to the server was lost after roughly 5 hours. The relevant part of my code looks like this:

if __name__ == "__main__":

    # logging settings
    log_level = logging.DEBUG
    logging.basicConfig(format="%(asctime)s - %(levelname)s - %(name)s - %(message)s:", level=log_level, datefmt="%Y-%m-%d %H:%M:%S")
    logging.getLogger("urllib3").setLevel(logging.CRITICAL)
    logging.getLogger("websocket").setLevel(logging.CRITICAL)

    # rdp authentication token
    rdp_token = RDPTokenManagement(bot_username, bot_password, app_key, 30)
    access_token, refresh_token, expire_time, logged_in = authen_rdp(rdp_token)
    if not access_token:
        sys.exit(1)

    # join chatrooms
    for chatroom in config["chatrooms"].keys():
        join_room = join_chatroom(access_token, chatroom)

    # connect via a websocket connection
    print(f"connecting to {ws_url}")
    web_socket_app = websocket.WebSocketApp(ws_url, on_message=on_message, on_error=on_error, on_close=on_close, subprotocols=["messenger-json"])
    web_socket_app.on_open = on_open

    # infinite event loop
    wst = threading.Thread(target=web_socket_app.run_forever, kwargs={"sslopt": {"check_hostname": False}})
    wst.start()

    try:

        while True:

            if int(expire_time) > 245:
                expire_time = "300"
                time.sleep(int(expire_time) - 245)
            else:
                sys.exit(1)

            if not web_socket_app.keep_running:
                print(f"{datetime.datetime.now()} new connection established")
                send_ws_connect_request(access_token)

            print(f"{datetime.datetime.now()} token refreshed")
            access_token, refresh_token, expire_time, logged_in = authen_rdp(rdp_token)

            if not access_token:
                sys.exit(1)

            if logged_in:
                send_ws_keepalive(access_token)

    except KeyboardInterrupt:

        web_socket_app.close()

So, if you have an idea, please let me know. Thanks.


The part with

if not web_socket_app.keep_running

was added just now.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.