source read sofa-bolt (3) - Communication Model

Bolt provides four communication models, which are Oneway , Sync , Future , the Callback Asynchronous

4.1 Oneway

oneway-way call

Feature

  • Do not care about the return value
  • Sending a request to return immediately
com.alipay.remoting.BaseRemoting#oneway
protected void oneway(final Connection conn, final RemotingCommand request) {
    try {
        conn.getChannel().writeAndFlush(request).addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture f) throws Exception {
                if (!f.isSuccess()) {
                    logger.error("Invoke send failed. The address is {}",
                        RemotingUtil.parseRemoteAddress(conn.getChannel()), f.cause());
                }
            }

        });
    } catch (Exception e) {
        if (null == conn) {
            logger.error("Conn is null");
        } else {
            logger.error("Exception caught when sending invocation. The address is {}",
                RemotingUtil.parseRemoteAddress(conn.getChannel()), e);
        }
    }
}

4.2 Sync

Sync synchronization request

Feature

  • We need to get a return value
  • If you do not return within the timeout period, a timeout error is triggered
protected RemotingCommand invokeSync(final Connection conn, final RemotingCommand request,
                                     final int timeoutMillis) throws RemotingException,
                                                             InterruptedException {
    final InvokeFuture future = createInvokeFuture(request, request.getInvokeContext());
    conn.addInvokeFuture(future);
    final int requestId = request.getId();
    try {
        conn.getChannel().writeAndFlush(request).addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture f) throws Exception {
                if (!f.isSuccess()) {
                    conn.removeInvokeFuture(requestId);
                    future.putResponse(commandFactory.createSendFailedResponse(
                        conn.getRemoteAddress(), f.cause()));
                    logger.error("Invoke send failed, id={}", requestId, f.cause());
                }
            }

        });
    } catch (Exception e) {
        conn.removeInvokeFuture(requestId);
        future.putResponse(commandFactory.createSendFailedResponse(conn.getRemoteAddress(), e));
        logger.error("Exception caught when sending invocation, id={}", requestId, e);
    }
    RemotingCommand response = future.waitResponse(timeoutMillis);

    if (response == null) {
        conn.removeInvokeFuture(requestId);
        response = this.commandFactory.createTimeoutResponse(conn.getRemoteAddress());
        logger.warn("Wait response, request id={} timeout!", requestId);
    }

    return response;
}

The above code is the code for the client sends a request, InvokeFuture is the realization DefaultInvokeFuture, CountDownLatch to achieve synchronization with the internal, initialization default values ​​CountDownLatch 1.

private final CountDownLatch     countDownLatch          = new CountDownLatch(1);

When calling putResponse, countDownLatch count by 1

@Override
public void putResponse(RemotingCommand response) {
    this.responseCommand = (ResponseCommand) response;
    this.countDownLatch.countDown();
}

Then return trigger waitResponse

@Override
public ResponseCommand waitResponse(long timeoutMillis) throws InterruptedException {
    this.countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
    return this.responseCommand;
}

Server returned to normal, putResponse where trigger it?

In RpcResponseProcessor class can be traced to putResponse

com.alipay.remoting.rpc.protocol.RpcResponseProcessor#doProcess
public void doProcess(RemotingContext ctx, RemotingCommand cmd) {

    Connection conn = ctx.getChannelContext().channel().attr(Connection.CONNECTION).get();
    InvokeFuture future = conn.removeInvokeFuture(cmd.getId());
    ClassLoader oldClassLoader = null;
    try {
        if (future != null) {
            if (future.getAppClassLoader() != null) {
                oldClassLoader = Thread.currentThread().getContextClassLoader();
                Thread.currentThread().setContextClassLoader(future.getAppClassLoader());
            }
            future.putResponse(cmd);
            future.cancelTimeout();
            try {
                future.executeInvokeCallback();
            } catch (Exception e) {
                logger.error("Exception caught when executing invoke callback, id={}",
                    cmd.getId(), e);
            }
        } else {
            logger
                .warn("Cannot find InvokeFuture, maybe already timeout, id={}, from={} ",
                    cmd.getId(),
                    RemotingUtil.parseRemoteAddress(ctx.getChannelContext().channel()));
        }
    } finally {
        if (null != oldClassLoader) {
            Thread.currentThread().setContextClassLoader(oldClassLoader);
        }
    }

}

4.3 Future

Future asynchronous requests, and synchronization of different requests, Futrue direct return InvokeFuture object thread to continue. Until the call InvokeFuture.get method, if the response has been returned, you can get the results directly, otherwise it will block the thread.

protected InvokeFuture invokeWithFuture(final Connection conn, final RemotingCommand request, final int timeoutMillis) {
    final InvokeFuture future = createInvokeFuture(request, request.getInvokeContext());
    conn.addInvokeFuture(future);
    final int requestId = request.getId();
    try {
        Timeout timeout = TimerHolder.getTimer().newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                InvokeFuture future = conn.removeInvokeFuture(requestId);
                if (future != null) {
                    future.putResponse(commandFactory.createTimeoutResponse(conn
                        .getRemoteAddress()));
                }
            }

        }, timeoutMillis, TimeUnit.MILLISECONDS);
        future.addTimeout(timeout);

        conn.getChannel().writeAndFlush(request).addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture cf) throws Exception {
                if (!cf.isSuccess()) {
                    InvokeFuture f = conn.removeInvokeFuture(requestId);
                    if (f != null) {
                        f.cancelTimeout();
                        f.putResponse(commandFactory.createSendFailedResponse(
                            conn.getRemoteAddress(), cf.cause()));
                    }
                    logger.error("Invoke send failed. The address is {}",
                        RemotingUtil.parseRemoteAddress(conn.getChannel()), cf.cause());
                }
            }

        });
    } catch (Exception e) {
        InvokeFuture f = conn.removeInvokeFuture(requestId);
        if (f != null) {
            f.cancelTimeout();
            f.putResponse(commandFactory.createSendFailedResponse(conn.getRemoteAddress(), e));
        }
        logger.error("Exception caught when sending invocation. The address is {}",
            RemotingUtil.parseRemoteAddress(conn.getChannel()), e);
    }
    return future;
}

4.4 Callback asynchronous

CallBack callback function asynchronous requests, compared with the Future can be passed to the callback function

protected void invokeWithCallback(final Connection conn, final RemotingCommand request,
                                  final InvokeCallback invokeCallback, final int timeoutMillis) {
    final InvokeFuture future = createInvokeFuture(conn, request, request.getInvokeContext(),
        invokeCallback);
    conn.addInvokeFuture(future);
    final int requestId = request.getId();
    try {
        Timeout timeout = TimerHolder.getTimer().newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                InvokeFuture future = conn.removeInvokeFuture(requestId);
                if (future != null) {
                    future.putResponse(commandFactory.createTimeoutResponse(conn
                        .getRemoteAddress()));
                    future.tryAsyncExecuteInvokeCallbackAbnormally();
                }
            }

        }, timeoutMillis, TimeUnit.MILLISECONDS);
        future.addTimeout(timeout);
        conn.getChannel().writeAndFlush(request).addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture cf) throws Exception {
                if (!cf.isSuccess()) {
                    InvokeFuture f = conn.removeInvokeFuture(requestId);
                    if (f != null) {
                        f.cancelTimeout();
                        f.putResponse(commandFactory.createSendFailedResponse(
                            conn.getRemoteAddress(), cf.cause()));
                        f.tryAsyncExecuteInvokeCallbackAbnormally();
                    }
                    logger.error("Invoke send failed. The address is {}",
                        RemotingUtil.parseRemoteAddress(conn.getChannel()), cf.cause());
                }
            }

        });
    } catch (Exception e) {
        InvokeFuture f = conn.removeInvokeFuture(requestId);
        if (f != null) {
            f.cancelTimeout();
            f.putResponse(commandFactory.createSendFailedResponse(conn.getRemoteAddress(), e));
            f.tryAsyncExecuteInvokeCallbackAbnormally();
        }
        logger.error("Exception caught when sending invocation. The address is {}",
            RemotingUtil.parseRemoteAddress(conn.getChannel()), e);
    }
}

Callback function performed by the observer pattern, InvokeCallbackListener perform onResponse or onException callback method based on the results of reponse


public void run() {
    InvokeCallback callback = future.getInvokeCallback();
    // a lot of try-catches to protect thread pool
    ResponseCommand response = null;

    try {
        response = (ResponseCommand) future.waitResponse(0);
    } catch (InterruptedException e) {
        String msg = "Exception caught when getting response from InvokeFuture. The address is "
                     + this.remoteAddress;
        logger.error(msg, e);
    }
    if (response == null || response.getResponseStatus() != ResponseStatus.SUCCESS) {
        try {
            Exception e;
            if (response == null) {
                e = new InvokeException("Exception caught in invocation. The address is "
                                        + this.remoteAddress + " responseStatus:"
                                        + ResponseStatus.UNKNOWN, future.getCause());
            } else {
                response.setInvokeContext(future.getInvokeContext());
                switch (response.getResponseStatus()) {
                    case TIMEOUT:
                        e = new InvokeTimeoutException(
                            "Invoke timeout when invoke with callback.The address is "
                                    + this.remoteAddress);
                        break;
                    case CONNECTION_CLOSED:
                        e = new ConnectionClosedException(
                            "Connection closed when invoke with callback.The address is "
                                    + this.remoteAddress);
                        break;
                    case SERVER_THREADPOOL_BUSY:
                        e = new InvokeServerBusyException(
                            "Server thread pool busy when invoke with callback.The address is "
                                    + this.remoteAddress);
                        break;
                    case SERVER_EXCEPTION:
                        String msg = "Server exception when invoke with callback.Please check the server log! The address is "
                                     + this.remoteAddress;
                        RpcResponseCommand resp = (RpcResponseCommand) response;
                        resp.deserialize();
                        Object ex = resp.getResponseObject();
                        if (ex instanceof Throwable) {
                            e = new InvokeServerException(msg, (Throwable) ex);
                        } else {
                            e = new InvokeServerException(msg);
                        }
                        break;
                    default:
                        e = new InvokeException(
                            "Exception caught in invocation. The address is "
                                    + this.remoteAddress + " responseStatus:"
                                    + response.getResponseStatus(), future.getCause());

                }
            }
            callback.onException(e);
        } catch (Throwable e) {
            logger
                .error(
                    "Exception occurred in user defined InvokeCallback#onException() logic, The address is {}",
                    this.remoteAddress, e);
        }
    } else {
        ClassLoader oldClassLoader = null;
        try {
            if (future.getAppClassLoader() != null) {
                oldClassLoader = Thread.currentThread().getContextClassLoader();
                Thread.currentThread().setContextClassLoader(future.getAppClassLoader());
            }
            response.setInvokeContext(future.getInvokeContext());
            RpcResponseCommand rpcResponse = (RpcResponseCommand) response;
            response.deserialize();
            try {
                callback.onResponse(rpcResponse.getResponseObject());
            } catch (Throwable e) {
                logger
                    .error(
                        "Exception occurred in user defined InvokeCallback#onResponse() logic.",
                        e);
            }
        } catch (CodecException e) {
            logger
                .error(
                    "CodecException caught on when deserialize response in RpcInvokeCallbackListener. The address is {}.",
                    this.remoteAddress, e);
        } catch (Throwable e) {
            logger.error(
                "Exception caught in RpcInvokeCallbackListener. The address is {}",
                this.remoteAddress, e);
        } finally {
            if (oldClassLoader != null) {
                Thread.currentThread().setContextClassLoader(oldClassLoader);
            }
        }
    } // enf of else
} // end of run

Guess you like

Origin www.cnblogs.com/huiyao/p/12417874.html