use of info.xiancloud.core.NotifyHandler in project xian by happyyangyuan.
the class RpcServerDefaultHandler method processMsg.
private void processMsg(final ChannelHandlerContext ctx, final JSONObject json) {
try {
IdManager.makeSureMsgId(json);
if (MessageType.isDefaultRequest(json)) {
UnitRequest request = json.toJavaObject(UnitRequest.class);
request.getContext().setFromRemote(true);
String group = request.getContext().getGroup(), unit = request.getContext().getUnit();
final Consumer<String> backPayloadConsumerOnFailure = payload -> {
LOG.info("rpc server --> client发送失败了,因此这里复用当前长连接响应消息");
ctx.writeAndFlush(payload + Constant.RPC_DELIMITER);
};
ISequencer.build(group, unit, json).sequence(// call this sender if sequencer is succeeded.
new DefaultLocalAsyncSender(request, new NotifyHandler() {
protected void handle(UnitResponse unitResponse) {
LocalNodeManager.sendBack(unitResponse, backPayloadConsumerOnFailure);
}
}), /*failed directly, call this handler*/
new NotifyHandler() {
protected void handle(UnitResponse failureOut) {
LocalNodeManager.sendBack(failureOut, backPayloadConsumerOnFailure);
}
});
} else if (MessageType.isDefaultResponse(json)) {
LOG.debug("这是非常重要的说明:" + "1、客户端发给外部节点的请求期待的响应内容,服务端节在准备好响应结果后立刻与请求端新建一个rpc长连接/复用已存在的长连接,将响应写回去;" + "2、停服务时本地server会先停止,server停止就会关闭socket和server的io线程池,由于server的io线程池和业务线程池是分离的," + "业务线程池会继续运行直到所有任务处理完毕为止。此时,本节点不再有能力接收外部请求了,但是:" + "a.在即将停止的节点内,业务线程池任然需要向外部发送请求以完成业务操作,以及得到响应结果,因此client必须保持打开的。" + "b.在即将停止的节点内,业务线程池需要将本地执行结果返回给远程,这时候server已停,无法复用原管道将结果写回去,因此必须使用依然存活的client" + "将结果写回。" + "因此,有如下逻辑:所有server优先复用当前管道将响应写回去,当SERVER关闭后,业务线程池中后续任务通过未停止的client回写响应结果。");
UnitResponse response = json.toJavaObject(UnitResponse.class);
String ssid = response.getContext().getSsid();
ThreadPoolManager.execute(() -> {
NotifyHandler callback = LocalNodeManager.handleMap.getIfPresent(ssid);
if (callback != null) {
LocalNodeManager.handleMap.invalidate(ssid);
callback.callback(UnitResponse.create(json));
} else {
LOG.error(String.format("ssid=%s的消息没有找到对应的notifyHandler!整个消息内容=%s,", ssid, json), new Throwable());
}
}, response.getContext().getMsgId());
} else
LOG.error("rpc server端只支持request和response两种消息类型,不支持:" + MessageType.getMessageType(json), new RuntimeException());
} catch (Throwable e) {
LOG.error(e);
} finally {
MsgIdHolder.clear();
}
}
use of info.xiancloud.core.NotifyHandler in project xian by happyyangyuan.
the class RuleController method work.
// 执行
private void work() {
if (next.equals(END)) {
end();
} else {
Map<String, Object> params = processParams();
LOG.info("[RuleController] params = " + params);
Xian.call(next.split("_")[0], next.split("_")[1], params, new NotifyHandler() {
protected void handle(UnitResponse unitResponse1) {
unitResponse = unitResponse1;
processReturnParams();
callNext();
work();
}
});
}
}
use of info.xiancloud.core.NotifyHandler in project xian by happyyangyuan.
the class BroadcastSender method asyncSend.
@Override
protected void asyncSend() throws UnitOfflineException, UnitUndefinedException {
List<UnitInstance> list = UnitRouter.singleton.allInstances(Unit.fullName(unitRequest.getContext().getGroup(), unitRequest.getContext().getUnit()));
UnitMeta.Broadcast broadcast = list.get(0).getPayload().getMeta().getBroadcast();
final CountDownLatch latch = new CountDownLatch(list.size());
Collection<Object> piledUpOutput = new ConcurrentLinkedQueue<>();
final NotifyHandler tmpHandler = new NotifyHandler() {
protected void handle(UnitResponse output) {
if (!broadcast.isSuccessDataOnly()) {
piledUpOutput.add(output);
} else if (output.succeeded()) {
piledUpOutput.add(output.getData());
}
latch.countDown();
}
};
for (UnitInstance unitInstance : list) {
if (unitInstance.getNodeId().equals(LocalNodeManager.LOCAL_NODE_ID)) {
// we must not share the same unitRequest object while sending request concurrently.
UnitRequest clonedUnitRequest = CloneUtil.cloneBean(unitRequest, UnitRequest.class);
/*clonedUnitRequest.getContext().setDestinationNodeId(unitInstance.getNodeId()); no need */
new RoutedLocalAsyncSender(clonedUnitRequest, tmpHandler).send();
} else {
LOG.debug("In order not to share the same unit request object,we clone a new request");
UnitRequest clonedRequest = CloneUtil.cloneBean(unitRequest, UnitRequest.class);
clonedRequest.getContext().setDestinationNodeId(unitInstance.getNodeId());
LocalNodeManager.send(clonedRequest, tmpHandler);
}
}
if (broadcast.isAsync()) {
callback.callback(UnitResponse.success());
} else {
try {
if (!latch.await(broadcast.getTimeoutInMilli(), TimeUnit.MILLISECONDS)) {
LOG.error(new TimeoutException());
callback.callback(UnitResponse.error(Group.CODE_TIME_OUT, piledUpOutput, "Time out while waiting for all the units to response, the data is only part of the result. "));
} else {
callback.callback(UnitResponse.success(piledUpOutput));
}
} catch (InterruptedException e) {
callback.callback(UnitResponse.exception(e));
}
}
}
use of info.xiancloud.core.NotifyHandler in project xian by happyyangyuan.
the class ReceiveAndBroadcast method execute.
@Override
public UnitResponse execute(UnitRequest msg) {
if (msg.getContext().isRouted()) {
return execute0(msg);
} else {
List<UnitInstance> list = new ArrayList<>();
String application = msg.get("application", String.class);
List<UnitInstance> unitInstances;
try {
unitInstances = UnitRouter.singleton.allInstances(Unit.fullName(getGroupName(), getUnitName()));
} catch (UnitOfflineException | UnitUndefinedException e) {
throw new RuntimeException(e);
}
if (StringUtil.isEmpty(application) || ALL.equals(application)) {
list.addAll(unitInstances);
} else {
for (UnitInstance clientInfo : unitInstances) {
if (clientInfo.getName().equals(msg.getString("application"))) {
list.add(clientInfo);
}
}
}
CountDownLatch latch = new CountDownLatch(list.size());
List<Object> piledUpOutput = new ArrayList<>();
for (UnitInstance clientInfo : list) {
LocalNodeManager.send(new UnitRequest().setContext(RequestContext.create().setGroup(getGroupName()).setUnit(getUnitName()).setDestinationNodeId(clientInfo.getNodeId())), new NotifyHandler() {
protected void handle(UnitResponse unitResponse) {
LOG.info("对" + clientInfo.getNodeId() + "执行" + getName() + "操作完毕");
if (!successDataOnly()) {
piledUpOutput.add(unitResponse);
} else if (unitResponse.succeeded()) {
piledUpOutput.add(unitResponse.getData());
}
latch.countDown();
}
});
}
if (async()) {
return UnitResponse.success();
} else {
try {
latch.await(timeoutInMilli(), TimeUnit.MILLISECONDS);
return UnitResponse.success(piledUpOutput);
} catch (InterruptedException e) {
return UnitResponse.exception(e);
}
}
}
}
use of info.xiancloud.core.NotifyHandler in project xian by happyyangyuan.
the class Node method send.
public UnitResponse send(UnitRequest request) {
String ssid = IdManager.nextSsid();
request.getContext().setSsid(ssid);
fillRequestContext(request.getContext());
UnitResponse unitResponse = UnitResponse.create(true);
final CountDownLatch latch = new CountDownLatch(1);
NotifyHandler handler = new NotifyHandler() {
public void handle(UnitResponse output) {
UnitResponse.copy(output, output);
latch.countDown();
}
};
handleMap.put(ssid, handler);
String payload = JSON.toJSONStringWithDateFormat(request, Constant.DATE_SERIALIZE_FORMAT);
publisher.p2pPublish(request.getContext().getDestinationNodeId(), payload);
try {
if (!latch.await(Constant.UNIT_DEFAULT_TIME_OUT_IN_MILLI, TimeUnit.MILLISECONDS)) {
handler.setTimeout(true);
return UnitResponse.error(Group.CODE_TIME_OUT, null, "Response time out!").setContext(UnitResponse.Context.create().setSsid(ssid));
}
} catch (InterruptedException e) {
return UnitResponse.exception(e);
}
return unitResponse;
}
Aggregations