EnvoyFilter to fix 503 errors with nodejs app (5sec KeepAlive)

Hello!
I have a lot of different nodejs apps (with default keepAlive timeout 5 sec).
Trying to decrease timeout in envoy from the default (1 hour? 300sec?) to 4 sec.
It seems to work as expected (no more 503 errors).
But I’m not sure that this is the right way, maybe I override (will override) some configuration (circuit breaker/outlier detection)?
And I can’t understand why common_http_protocol_options can be configured in a Cluster and also in HTTP Filter. What will take precedence?

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: fix-for-nodejs
  namespace: "istio-system"
spec:
  configPatches:
  - applyTo: CLUSTER
    match:
      cluster:
      context: SIDECAR_OUTBOUND
    patch:
      operation: MERGE
      value:
        typed_extension_protocol_options:
          envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
            '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
            common_http_protocol_options:
              idle_timeout: 4s
            use_downstream_protocol_config: 
              http2_protocol_options: {}
              http_protocol_options: {}
  - applyTo: CLUSTER
    match:
      cluster:
      context: SIDECAR_INBOUND
    patch:
      operation: MERGE
      value:
        typed_extension_protocol_options:
          envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
            '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
            common_http_protocol_options:
              idle_timeout: 4s
            use_downstream_protocol_config: 
              http2_protocol_options: {}
              http_protocol_options: {}

Also the script for K6 for load test (with it I was able to reproduce and confirm that there is no more 503 errors)

import http from 'k6/http';
import { sleep,check } from 'k6';

export const options = {
  discardResponseBodies: false,
  scenarios: {
    storm: {
      executor: 'ramping-vus',
      startVUs: 50,
      stages: [
        { duration: '120s', target: 100 },
        { duration: '120s', target: 0 },
      ],
      gracefulRampDown: '10s',
    },
  },
};

export default function () {

  const url = 'https://staging.example.com/api/v1/ping';

  const params = {
    "timeout": "120s"
  };

  const res = http.get(url, params);

  let passed = check(res, {
    'is status 200': (r) => r.status === 200
  });

  if (!passed) {
    console.log(`Request to ${res.request.url} with status ${res.status} failed the checks!`, JSON.stringify(res));
  }

  //sleep(1);
}

The first question I’m trying to understand, what is the difference common_http_protocol_options in CLUSTER and in HTTP connection manager

I mean, for example, if I set idle_timeout=4s in CLUSTER and idle_timeout=300s in HTTP connection manager which one will actually work?

I see this in the doc, but can’t understand the flow

To modify the idle timeout for downstream connections use the common_http_protocol_options field in the HTTP connection manager configuration. To modify the idle timeout for upstream connections use the common_http_protocol_options field in the Cluster’s extension_protocol_options, keyed by HttpProtocolOptions