Skip to content

Infinite loop in LoadBalancingCall.doPick after closing the client #2786

Closed
@alexeevg

Description

@alexeevg

Problem description

If the grpc.closeClient call is racing with new request creation, the latter can trigger the infinite loop in the LoadBalancingCall.doPick method.

Reproduction steps

For full reproduction code please refer to this commit.

In a nutshell, the issue is reproduced by the following code:

function makeRequest(client) {
  return new Promise((resolve, reject) => {
    client.unaryEcho({message: 'infinite loop demo'}, (error, value) => {
      if (error) {
        return reject(error);
      }
      resolve(value);
    });
  });
}

async function main() {
  let argv = parseArgs(process.argv.slice(2), {
    string: 'target',
    default: {target: 'localhost:50052'}
  });
  
  for (let i = 0; i < 20; i++) {
    const client = new echoProto.Echo(argv.target, grpc.credentials.createInsecure());
    await makeRequest(client);
    const calls =  Array.from({length: 20}).map(() => makeRequest(client));
    grpc.closeClient(client);
    await Promise.all(calls);
  }
}

main();

The app never terminates, blocks the event loop, consumes 100% CPU, and if run with GRPC_TRACE=load_balancing_call, produces logs like these:

D 2024-07-06T17:43:52.591Z | v1.10.10 11419 | load_balancing_call | [84] Pick called
D 2024-07-06T17:43:52.591Z | v1.10.10 11419 | load_balancing_call | [84] Pick result: COMPLETE subchannel: (1) 127.0.0.1:50052 status: undefined undefined
D 2024-07-06T17:43:52.591Z | v1.10.10 11419 | load_balancing_call | [84] Picked subchannel (1) 127.0.0.1:50052 has state IDLE after getting credentials metadata. Retrying pick
D 2024-07-06T17:43:52.591Z | v1.10.10 11419 | load_balancing_call | [84] Pick called
D 2024-07-06T17:43:52.591Z | v1.10.10 11419 | load_balancing_call | [84] Pick result: COMPLETE subchannel: (1) 127.0.0.1:50052 status: undefined undefined
D 2024-07-06T17:43:52.591Z | v1.10.10 11419 | load_balancing_call | [84] Picked subchannel (1) 127.0.0.1:50052 has state IDLE after getting credentials metadata. Retrying pick

Environment

  • OS name, version and architecture: [OSX 14.4.1]
  • Node version [18.20.3]
  • Node installation method [nvm]
  • Package name and version [@grpc/[email protected]]

Additional context

The issue looks similar to #2604 but this one is present in the latest grpc-js version.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions