Skip to content

http.Agent tcp keepalive not working #41965

Open
@JohnTJohnston

Description

@JohnTJohnston

Version

v16.14.0

Platform

Linux ip-192-168-4-97.us-west-2.compute.internal 5.10.96-90.460.amzn2.x86_64 #1 SMP Fri Feb 4 17:12:04 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

http

What steps will reproduce the bug?

Client:

"use strict";

const http = require("http");

(async function main() {

    process.env.SERVER_HOST = process.env.SERVER_HOST || "192.168.4.155";
    process.env.SERVER_PORT = process.env.SERVER_PORT || 3000;

    await issueRequest();

})();

async function issueRequest() {

    const request = http.request({
        host   : process.env.SERVER_HOST,
        port   : process.env.SERVER_PORT,
        path   : "/tcp-keepalive-test",
        method : "GET",
        agent  : new http.Agent({
            keepAlive      : true,
            keepAliveMsecs : 1000 * 10,
        }),
    });

    const start = new Date();

    const result = await new Promise(resolve => {

        request.on("response", response => {

            let responseBody = "";

            response.on("data", data => {
                responseBody += data;
            });

            response.on("end", () => {
                resolve(responseBody);
            });
        });

        request.end();
    });

    const stop = new Date();

    console.log(`start: ${start.toISOString()}, stop: ${stop.toISOString()}, result: ${result}`);
}

Server:

"use strict";

const http = require("http");

(function main() {

    process.env.SERVER_PORT = process.env.SERVER_PORT || 3000;

    const server = http.createServer(async (req, resp) => {
        await new Promise(resolve => setTimeout(resolve, 1000 * 60 * 5));
        resp.statusCode = 200;
        resp.end("success");
    });

    server.listen(process.env.SERVER_PORT);

})();

How often does it reproduce? Is there a required condition?

100% reproducible.

What is the expected behavior?

TCP keepalive packets should be seen in the TCP stream every 10 seconds. This shows all of the packets between client and server and the keepalives are absent:

[ec2-user@ip-192-168-4-97 testv3]$ tshark -r keepalive.pcap ip.addr == 192.168.4.155
 50          9 192.168.4.97 -> 192.168.4.155 TCP 74 57602 > hbci [SYN] Seq=0 Win=62727 Len=0 MSS=8961 SACK_PERM=1 TSval=1629361317 TSecr=0 WS=128
 51          9 192.168.4.155 -> 192.168.4.97 TCP 74 hbci > 57602 [SYN, ACK] Seq=0 Ack=1 Win=26847 Len=0 MSS=8961 SACK_PERM=1 TSval=2679957088 TSecr=1629361317 WS=128
 52          9 192.168.4.97 -> 192.168.4.155 TCP 66 57602 > hbci [ACK] Seq=1 Ack=1 Win=62848 Len=0 TSval=1629361317 TSecr=2679957088
 53          9 192.168.4.97 -> 192.168.4.155 HTTP 152 GET /tcp-keepalive-test HTTP/1.1
 54          9 192.168.4.155 -> 192.168.4.97 TCP 66 hbci > 57602 [ACK] Seq=1 Ack=87 Win=26880 Len=0 TSval=2679957090 TSecr=1629361319
188        309 192.168.4.155 -> 192.168.4.97 HTTP 195 HTTP/1.1 200 OK
191        309 192.168.4.97 -> 192.168.4.155 TCP 66 57602 > hbci [ACK] Seq=87 Ack=130 Win=62720 Len=0 TSval=1629661377 TSecr=2680257146
194        309 192.168.4.97 -> 192.168.4.155 TCP 66 57602 > hbci [FIN, ACK] Seq=87 Ack=130 Win=62720 Len=0 TSval=1629661383 TSecr=2680257146
195        309 192.168.4.155 -> 192.168.4.97 TCP 66 hbci > 57602 [FIN, ACK] Seq=130 Ack=88 Win=26880 Len=0 TSval=2680257153 TSecr=1629661383
196        309 192.168.4.97 -> 192.168.4.155 TCP 66 57602 > hbci [ACK] Seq=88 Ack=131 Win=62720 Len=0 TSval=1629661384 TSecr=2680257153

This shows all captured keepalive packets, and the only keepalives present are associated with the ssh session used to invoke the client:

[ec2-user@ip-192-168-4-97 testv3]$ tshark -r keepalive.pcap tcp.analysis.keep_alive
 60         30 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170273892 TSecr=3357619098
 66         51 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170294372 TSecr=3357640683
 72         71 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170314852 TSecr=3357661163
 78         92 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170335332 TSecr=3357681643
 86        112 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170355812 TSecr=3357702123
 91        133 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170376292 TSecr=3357722603
 99        153 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170396772 TSecr=3357743083
107        174 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170417252 TSecr=3357763563
153        194 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170437732 TSecr=3357784043
157        215 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170458212 TSecr=3357804523
167        235 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170478692 TSecr=3357825003
171        256 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170499172 TSecr=3357845483
178        276 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170519652 TSecr=3357865963
184        297 192.168.1.39 -> 192.168.4.97 TCP 66 [TCP Keep-Alive] 42370 > ssh [ACK] Seq=556 Ack=1265 Win=885 Len=0 TSval=170540132 TSecr=3357886443

What do you see instead?

No keepalive packets are captured.

Additional information

The motivation for this is to solve a problem we have in AWS where long running transactions complete successfully, yet the result is not returned to the client. Packet captures in this environment show that there are no keepalives.

Metadata

Metadata

Assignees

No one assigned

    Labels

    httpIssues or PRs related to the http subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions