In a website which uses gin-gonic
as webserver and nginx
as a proxy server, clients send their data to the server via gin-gonic
exposed APIs, and — in order to send server commands to clients — each one(i.e client) has a connection to the web server which it keeps for a long time(i.e does not expire it for several hours) and fill their response body with the desired command (for bidirectional connection, we can use ws
instead of that).
The problem is, we need to know if a client drop/canceled its connection with the server. In order to understand that we have this line case <-c.Request.Context().Done():
in the following code.
func MakeConnection(c *gin.Context) {
// ... code
select {
case notification = <-clientModel.Channels[token]:// we have a command to send to user
log.Info("Notification")
err = nil
case <-c.Request.Context().Done(): // connection dropped by client
log.Info("Cancel")
err = c.Err()
case <-ctx.Done(): // time elapsed and there was no command to send to client
log.Info("timeout")
err = errors.New("timeout exceeded")
}
// ... code
}
Everything works well (if we make such a connection to the server and cancel it after arbitrary time, immediately Cancel
displayed in the terminal) until the count of clients increases.
For about 5 clients this work as expected but for more than 10 clients(more load) although nginx
logs cancellation in its access log(as error code 499
) but webserver (i.e gin-gonic
) does not get notified.
nginx
configuration
server {
# SSL configuration
listen 443 ssl http2 so_keepalive=10:150:1;
listen [::]:443 ssl http2 so_keepalive=10:150:1;
include /etc/nginx/snippets/self-signed.conf;
include /etc/nginx/snippets/ssl-params.conf;
root /var/www/project;
autoindex off;
location / {
try_files $uri $uri/ @proxy;
}
location ~ /v1/v/[0-9a-zA-Z]+/notification {
proxy_connect_timeout 86460;
proxy_send_timeout 86460;
proxy_read_timeout 86460;
send_timeout 86460;
proxy_pass http://example_host:8002;
}
}
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
limit_req_zone $binary_remote_addr zone=req_zone:200m rate=10r/s;
limit_req_zone $request_uri zone=search_limit:100m rate=5r/s;
limit_req_zone $binary_remote_addr zone=login_limit:100m rate=20r/m;
vhost_traffic_status_zone;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
gzip_types text/html text/css text/javascript text/xml text/plain
image/x-icon image/svg+xml
application/rss+xml application/javascript application/x-javascript
application/xml application/xhtml+xml
application/x-font application/x-font-truetype application/x-font-ttf application/x-font-otf application/x-font-opentype application/vnd.ms-fontobject font/ttf font/otf font/opentype
font/woff font/ttf
application/octet-stream;
gzip_vary on;
include /etc/nginx/conf.d/*.conf;
}
nginx
does not send cancellation to web server. Moreover sincenginx
logs the cancellation I think it is not relevant to timeout duration... – Facilengixn
configuration added. Could you find anything there? – Facile