wandenberg / nginx-push-stream-module

A pure stream http push technology for your Nginx setup. Comet made easy and really scalable.
Other
2.22k stars 295 forks source link

Ping message interval not working #190

Closed geekuillaume closed 8 years ago

geekuillaume commented 9 years ago

Hello, First thanks for your project. It helps us a lot !

I've set the variable push_stream_ping_message_interval to 30s but using WebSocket, no ping message is sent. This result in a disconnection every 15m (I've set the push_stream_subscriber_connection_ttl variable to 15m).

Here is the result of nginx -V:

nginx version: nginx/1.8.0
built by gcc 4.9.2 (Ubuntu 4.9.2-10ubuntu13) 
configure arguments: --add-module=../nginx-push-stream-module

And the configuration:

pid         logs/nginx.pid;
error_log   stderr debug;

master_process      off;
worker_rlimit_core  2500M;
working_directory /tmp;

worker_processes    auto;
worker_rlimit_nofile 65535;

events {
    worker_connections  20000;
    use epoll;
    multi_accept on;
}

http {
    access_log      stdout;

    keepalive_timeout  0;

    push_stream_shared_memory_size                100m;
    push_stream_max_channel_id_length             200;
    push_stream_ping_message_interval             10s;
    push_stream_subscriber_connection_ttl         1m;
    push_stream_longpolling_connection_ttl        30s;
    push_stream_timeout_with_body                 off;

    push_stream_authorized_channels_only        off;

    push_stream_allowed_origins                 "*";

    push_stream_ping_message_text               "ping";

    server {
        listen          42632;

        server_name     localhost;

        location /channels-stats {
            push_stream_channels_statistics;
            push_stream_channels_path               $arg_id;
            allow   127.0.0.1;
            deny    all;
        }

        location /pub {
            push_stream_publisher admin;
            push_stream_channels_path               $arg_id;
            client_max_body_size                    32k;
            client_body_buffer_size                 32k;
            allow   127.0.0.1;
            deny    all;
        }

        location ~ /sub/(.*) {
            push_stream_subscriber;
            push_stream_channels_path                   $1;
        }

        location ~ /ev/(.*) {
            push_stream_subscriber eventsource;
            push_stream_channels_path                   $1;
        }

        location ~ /lp/(.*) {
            push_stream_subscriber      long-polling;
            push_stream_channels_path         $1;
        }

        location ~ /ws/(.*) {
            push_stream_subscriber websocket;
            push_stream_channels_path                   $1;
        }
    }
}

I know that if I don't set the push_stream_subscriber_connection_ttl variable I will not have connection drops but it can cause some dead connections to be still handled and using ressources right ?

Thanks for your help, Guillaume

edpelesh commented 9 years ago

Same problem for me. Client doesn't receive pings and can't send pings/pongs either (not sure they are accepted as it still gets disconnected after push_stream_subscriber_connection_ttl expires).

And if it works, will the client be able to answer it when push_stream_websocket_allow_publish off is set?

wandenberg commented 9 years ago

The ping message on websocket is only the PING frame specified at the RFC. This frame does not fire the onmessage callback. The client only respond with a PONG frame.

The push_stream_subscriber_connection_ttl is not for an inactivity period. The connection will be closed after this time, having messages or not.

Also, the PING/PONG frames are not related with the push_stream_websocket_allow_publish. This directive only controls if a received TEXT frame will be added to the channel or not.

To see all this points you can use a proxy like "Charles proxy" or even the chrome inspector on network tab.

edpelesh commented 9 years ago

I do understand that these are control frames with opcode 0x9 for PING and 0xA for PONG. But still, they are not present in Charles and Chrome Dev Tools. Log from https://github.com/square/SocketRocket doesn't show anything either. We may be doing something wrong or this could be a bug in websocket ping/pong handler.

Off-topic: is there a way to reset push_stream_subscriber_connection_ttl based on last received message? The case is when using mobile network, a connection may suddenly go away and socket can't close appropriately. I want to close it as soon as possible, so the value for push_stream_subscriber_connection_ttl is 1m. This scenario forces client to constantly reconnect every minute. Is there already a solution for this behavior? Thanks in advance.

natnet00 commented 8 years ago

I'd turn off ping messages and use TCP keepalive instead. Nginx supports TCP keepalive as option to the listen directive. That way you can shut down connections that don't respond to TCP keepalive packets.

wandenberg commented 8 years ago

@edpelesh sorry for the long time without an answer, I missed your message. About the PING / PONG, frames they really doesn't show on Chrome Dev Tools, but Charles does, image bellow (I'm using version 3.11.2 at ubuntu). I didn't checked the code of the SocketRocket client, so I can not say if it is right or not.

Regarding your suggestion to base the connection ttl on the last received message, it is a good idea. The problems are, on this scenario that a connection suddenly go away, the connection may still opened at server side for a undetermined period since the disconnect timer is postponed on each published message. And also a potential performance issue to remove the old timer and set a new one on each published message. But, can you create a new issue with this topic to discuss and try to implement a solution?

@natnet00 one of the purposes to ping messages is to always have some data traffic on the connection avoiding some proxy or router closes the connection, since they may guess that the connection is not in use if it still without traffic for some time. Keepalive make more sense on subsequent connections, and you should enable it, but on stream connections like websocket with the change that is done on the protocol, not so much.

ping_pong_frames

natnet00 commented 8 years ago

@wandenberg you got me wrong ;) I don't mean HTTP Keepalive. I mean TCP Keepalive (completely different). http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html

TCP Keepalive is exactly for the case that you describe: for telling routers or proxies not to close open connections. If there is no traffic on the TCP connection for a specific period, then a keepalive packet will be sent (and this is retried 2x, but the count is also configurable). If there is no reply the TCP connection will be closed on the server.

Nginx has support for this socket option via its listen directive: http://nginx.org/en/docs/http/ngx_http_core_module.html#listen and the so_keepalive parameter.

mkonecny commented 7 years ago

@natnet00 The link you gave is exactly what ping/pong is. A message at the application layer between two endpoints. It's something that you need to implement yourself if you do it at the TCP layer, while WebSockets gives you this implementation for free