async joinGroup({
    groupId,
    sessionTimeout,
    rebalanceTimeout,
    memberId = '',
    protocolType = 'consumer',
    groupProtocols,
  }) {
    const joinGroup = this.lookupRequest(apiKeys.JoinGroup, requests.JoinGroup)
    const makeRequest = (assignedMemberId = memberId) =>
      this[PRIVATE.SEND_REQUEST](
        joinGroup({
          groupId,
          sessionTimeout,
          rebalanceTimeout,
          memberId: assignedMemberId,
          protocolType,
          groupProtocols,
        })
      )

    try {
      return await makeRequest()
    } catch (error) {
      if (error.name === 'KafkaJSMemberIdRequired') {
        return makeRequest(error.memberId)
      }

      throw error
    }
  }
@public
@param {object} request
@param {string} request.groupId The unique group id
@param {number} request.sessionTimeout The coordinator considers the consumer dead if it receives
                               no heartbeat after this timeout in ms
@param {number} request.rebalanceTimeout The maximum time that the coordinator will wait for each member
                                 to rejoin when rebalancing the group
@param {string} [request.memberId=""] The assigned consumer id or an empty string for a new consumer
@param {string} [request.protocolType="consumer"] Unique name for class of protocols implemented by group
@param {Array} request.groupProtocols List of protocols that the member supports (assignment strategy)
                               [{ name: 'AssignerName', metadata: '{"version": 1, "topics": []}' }]
@returns {Promise}