aws / aws-sdk-js-v3

Modularized AWS SDK for JavaScript.
Apache License 2.0
3.03k stars 569 forks source link

`client.destroy()` does not stop a CloudWatch Logs Live Tail session #6392

Open mnapoli opened 3 weeks ago

mnapoli commented 3 weeks ago

Checkboxes for prior research

Describe the bug

The documentation states that a Logs live tail session can be stopped by calling client.destroy(): https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/example_cloudwatch-logs_StartLiveTail_section.html

    const client = new CloudWatchLogsClient();

    const command = new StartLiveTailCommand({
        logGroupIdentifiers: logGroupIdentifiers,
        logStreamNames: logStreamNames,
        logEventFilterPattern: filterPattern
    });
    try{
        const response = await client.send(command);
        handleResponseAsync(response);
    } catch (err){
        // Pre-stream exceptions are captured here
        console.log(err);
    }

    /* Set a timeout to close the client. This will stop the Live Tail session. */
    setTimeout(function() {
        console.log("Client timeout");
        client.destroy();
      }, 10000);

However that doesn't work, the session still runs.

I think this is the same problem as https://github.com/aws/aws-sdk-js-v3/issues/3922 with the Transcribe client. This issue was fixed in https://github.com/aws/aws-sdk-js-v3/pull/4400 by adding code in destroy().

If we look at the code, the destroy() method doesn't do anything: https://github.com/aws/aws-sdk-js-v3/blob/d9a4bcc98d7d9ab4fba5d6ca94f5e6e2273407bb/clients/client-cloudwatch-logs/src/CloudWatchLogsClient.ts#L664-L666

SDK version number

"@aws-sdk/client-cloudwatch-logs": "^3.632.0"

Which JavaScript Runtime is this issue in?

Browser

Details of the browser/Node.js/ReactNative version

Chrome

Reproduction Steps

    const client = new CloudWatchLogsClient();

    const command = new StartLiveTailCommand({
        logGroupIdentifiers: logGroupIdentifiers,
        logStreamNames: logStreamNames,
        logEventFilterPattern: filterPattern
    });
    try{
        const response = await client.send(command);
        handleResponseAsync(response);
    } catch (err){
        // Pre-stream exceptions are captured here
        console.log(err);
    }

    /* Set a timeout to close the client. This will stop the Live Tail session. */
    setTimeout(function() {
        console.log("Client timeout");
        client.destroy();
      }, 10000);

Observed Behavior

The async function is still called, the HTTP request is not closed.

Expected Behavior

The HTTP request is closed and the async function no longer receives events.

Possible Solution

No response

Additional Information/Context

I think this is the same problem as https://github.com/aws/aws-sdk-js-v3/issues/3922 with the Transcribe client. This issue was fixed in https://github.com/aws/aws-sdk-js-v3/pull/4400 by adding code in destroy().

If we look at the code, the destroy() method doesn't do anything: https://github.com/aws/aws-sdk-js-v3/blob/d9a4bcc98d7d9ab4fba5d6ca94f5e6e2273407bb/clients/client-cloudwatch-logs/src/CloudWatchLogsClient.ts#L664-L666

mnapoli commented 3 weeks ago

Workaround: use AbortController.

        const abortTail = new AbortController();

        const response = await cloudWatch.send(new StartLiveTailCommand({
            logGroupIdentifiers: logGroupArns,
        }), {
            abortSignal: abortTail.signal,
        });

        // Later
        abortTail.abort();

I think this is what the docs should advertise… Much cleaner as well than killing the whole client.

zshzbh commented 3 weeks ago

Hey @mnapoli ,

Thanks for the feedback! I can't reproduce this issue.

The code I have. -

import {StartLiveTailCommand, CloudWatchLogsClient} from "@aws-sdk/client-cloudwatch-logs";
const client = new CloudWatchLogsClient();

const command = new StartLiveTailCommand({
  logGroupIdentifiers: ["//myArn"],
});
try {
  const response = await client.send(command);
console.log(response)
} catch (err) {
  // Pre-stream exceptions are captured here
  console.log(err);
}

/* Set a timeout to close the client. This will stop the Live Tail session. */
setTimeout(function () {
  console.log("Client timeout");
  client.destroy();
}, 10000);

The result I got -

{
  '$metadata': {
    httpStatusCode: 200,
    requestId: '66d21c5a-a612-47c4-aae1-ffbb08ccdf81',
    extendedRequestId: undefined,
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  },
  responseStream: SmithyMessageDecoderStream {
    options: {
      messageStream: [MessageDecoderStream],
      deserializer: [AsyncFunction (anonymous)]
    }
  }
}
Client timeout

The session stopped and Client timeout is displayed. To narrow down the root cause, could you please replace handleResponseAsync(response); to console.log("res",response) and see if the issue persists?

For the destroy() method, we defined the destroy() as a default method for clients here in smithy pkg : https://github.com/smithy-lang/smithy-typescript/blob/main/packages/smithy-client/src/client.ts#L89

mnapoli commented 3 weeks ago

Thanks for the reply, did you try in Node or in a browser? (I have the problem in a browser, I can see the HTTP request still open and receiving more data forever after destroy())