public void changeInvisibleTimeAsync(//
        final String brokerName,
        final String addr, //
        final ChangeInvisibleTimeRequestHeader requestHeader,//
        final long timeoutMillis,
        final AckCallback ackCallback
    ) throws RemotingException, MQBrokerException, InterruptedException {
        final RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader);
        this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
            @Override
            public void operationComplete(ResponseFuture responseFuture) {

            }

            @Override
            public void operationSucceed(RemotingCommand response) {
                try {
                    ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) response.decodeCommandCustomHeader(ChangeInvisibleTimeResponseHeader.class);
                    AckResult ackResult = new AckResult();
                    if (ResponseCode.SUCCESS == response.getCode()) {
                        ackResult.setStatus(AckStatus.OK);
                        ackResult.setPopTime(responseHeader.getPopTime());
                        ackResult.setExtraInfo(ExtraInfoUtil
                            .buildExtraInfo(requestHeader.getOffset(), responseHeader.getPopTime(), responseHeader.getInvisibleTime(),
                                responseHeader.getReviveQid(), requestHeader.getTopic(), brokerName, requestHeader.getQueueId()) + MessageConst.KEY_SEPARATOR
                            + requestHeader.getOffset());
                    } else {
                        ackResult.setStatus(AckStatus.NO_EXIST);
                    }
                    ackCallback.onSuccess(ackResult);
                } catch (Exception e) {
                    ackCallback.onException(e);
                }
            }

            @Override
            public void operationFail(Throwable throwable) {
                ackCallback.onException(throwable);
            }
        });
    }
@Test
    public void testChangeInvisibleTimeAsync_Success() throws Exception {
        doAnswer((Answer<Void>) mock -> {
            InvokeCallback callback = mock.getArgument(3);
            RemotingCommand request = mock.getArgument(1);
            ResponseFuture responseFuture = new ResponseFuture(null, request.getOpaque(), 3 * 1000, null, null);
            RemotingCommand response = RemotingCommand.createResponseCommand(ChangeInvisibleTimeResponseHeader.class);
            response.setOpaque(request.getOpaque());
            response.setCode(ResponseCode.SUCCESS);
            ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) response.readCustomHeader();
            responseHeader.setPopTime(System.currentTimeMillis());
            responseHeader.setInvisibleTime(10 * 1000L);
            responseFuture.setResponseCommand(response);
            callback.operationSucceed(responseFuture.getResponseCommand());
            return null;
        }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any(InvokeCallback.class));

        final CountDownLatch done = new CountDownLatch(1);
        ChangeInvisibleTimeRequestHeader requestHeader = new ChangeInvisibleTimeRequestHeader();
        requestHeader.setTopic(topic);
        requestHeader.setQueueId(0);
        requestHeader.setOffset(0L);
        requestHeader.setInvisibleTime(10 * 1000L);
        mqClientAPI.changeInvisibleTimeAsync(brokerName, brokerAddr, requestHeader, 10 * 1000, new AckCallback() {
            @Override
            public void onSuccess(AckResult ackResult) {
                assertThat(ackResult.getStatus()).isEqualTo(AckStatus.OK);
                done.countDown();
            }

            @Override
            public void onException(Throwable e) {
                Assertions.fail("want no exception but got one", e);
                done.countDown();
            }
        });
        done.await();
    }