Max count of sessions per device

This commit is contained in:
Andrew Shvayka 2018-05-27 22:22:53 +03:00
parent 4007196d32
commit ea0585f3d9
7 changed files with 38 additions and 9 deletions

View File

@ -203,6 +203,10 @@ public class ActorSystemContext {
@Getter @Getter
private long queuePartitionId; private long queuePartitionId;
@Value("${actors.session.max_concurrent_sessions_per_device:1}")
@Getter
private long maxConcurrentSessionsPerDevice;
@Value("${actors.session.sync.timeout}") @Value("${actors.session.sync.timeout}")
@Getter @Getter
private long syncSessionTimeout; private long syncSessionTimeout;

View File

@ -81,6 +81,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -117,7 +118,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
super(systemContext, logger); super(systemContext, logger);
this.tenantId = tenantId; this.tenantId = tenantId;
this.deviceId = deviceId; this.deviceId = deviceId;
this.sessions = new HashMap<>(); this.sessions = new LinkedHashMap<>();
this.attributeSubscriptions = new HashMap<>(); this.attributeSubscriptions = new HashMap<>();
this.rpcSubscriptions = new HashMap<>(); this.rpcSubscriptions = new HashMap<>();
this.toDeviceRpcPendingMap = new HashMap<>(); this.toDeviceRpcPendingMap = new HashMap<>();
@ -501,6 +502,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
FromDeviceMsg inMsg = msg.getPayload(); FromDeviceMsg inMsg = msg.getPayload();
if (inMsg instanceof SessionOpenMsg) { if (inMsg instanceof SessionOpenMsg) {
logger.debug("[{}] Processing new session [{}]", deviceId, sessionId); logger.debug("[{}] Processing new session [{}]", deviceId, sessionId);
if (sessions.size() >= systemContext.getMaxConcurrentSessionsPerDevice()) {
SessionId sessionIdToRemove = sessions.keySet().stream().findFirst().orElse(null);
if (sessionIdToRemove != null) {
closeSession(sessionIdToRemove, sessions.remove(sessionIdToRemove));
}
}
sessions.put(sessionId, new SessionInfo(SessionType.ASYNC, msg.getServerAddress())); sessions.put(sessionId, new SessionInfo(SessionType.ASYNC, msg.getServerAddress()));
if (sessions.size() == 1) { if (sessions.size() == 1) {
reportSessionOpen(); reportSessionOpen();
@ -528,13 +535,15 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
} }
void processCredentialsUpdate() { void processCredentialsUpdate() {
sessions.forEach((k, v) -> { sessions.forEach(this::closeSession);
sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(new SessionCloseNotification(), k), v.getServer());
});
attributeSubscriptions.clear(); attributeSubscriptions.clear();
rpcSubscriptions.clear(); rpcSubscriptions.clear();
} }
private void closeSession(SessionId sessionId, SessionInfo sessionInfo) {
sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(new SessionCloseNotification(), sessionId), sessionInfo.getServer());
}
void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) {
this.deviceName = msg.getDeviceName(); this.deviceName = msg.getDeviceName();
this.deviceType = msg.getDeviceType(); this.deviceType = msg.getDeviceType();

View File

@ -56,12 +56,14 @@ class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor {
@Override @Override
protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) {
updateSessionCtx(msg, SessionType.ASYNC); updateSessionCtx(msg, SessionType.ASYNC);
if (firstMsg) {
toDeviceMsg(new SessionOpenMsg()).ifPresent(m -> forwardToAppActor(ctx, m));
firstMsg = false;
}
DeviceToDeviceActorMsg pendingMsg = toDeviceMsg(msg); DeviceToDeviceActorMsg pendingMsg = toDeviceMsg(msg);
FromDeviceMsg fromDeviceMsg = pendingMsg.getPayload(); FromDeviceMsg fromDeviceMsg = pendingMsg.getPayload();
if (firstMsg) {
if (fromDeviceMsg.getMsgType() != SessionMsgType.SESSION_OPEN) {
toDeviceMsg(new SessionOpenMsg()).ifPresent(m -> forwardToAppActor(ctx, m));
}
firstMsg = false;
}
switch (fromDeviceMsg.getMsgType()) { switch (fromDeviceMsg.getMsgType()) {
case POST_TELEMETRY_REQUEST: case POST_TELEMETRY_REQUEST:
case POST_ATTRIBUTES_REQUEST: case POST_ATTRIBUTES_REQUEST:

View File

@ -97,7 +97,7 @@ public class DefaultDeviceRpcService implements DeviceRpcService {
@Override @Override
public void processRpcResponseFromDevice(FromDeviceRpcResponse response) { public void processRpcResponseFromDevice(FromDeviceRpcResponse response) {
log.error("[{}] response the request: [{}]", this.hashCode(), response.getId()); log.error("[{}] response to request: [{}]", this.hashCode(), response.getId());
if (routingService.getCurrentServer().equals(response.getServerAddress())) { if (routingService.getCurrentServer().equals(response.getServerAddress())) {
UUID requestId = response.getId(); UUID requestId = response.getId();
Consumer<FromDeviceRpcResponse> consumer = localRpcRequests.remove(requestId); Consumer<FromDeviceRpcResponse> consumer = localRpcRequests.remove(requestId);

View File

@ -227,6 +227,7 @@ actors:
tenant: tenant:
create_components_on_init: true create_components_on_init: true
session: session:
max_concurrent_sessions_per_device: "${ACTORS_MAX_CONCURRENT_SESSION_PER_DEVICE:1}"
sync: sync:
# Default timeout for processing request using synchronous session (HTTP, CoAP) in milliseconds # Default timeout for processing request using synchronous session (HTTP, CoAP) in milliseconds
timeout: "${ACTORS_SESSION_SYNC_TIMEOUT:10000}" timeout: "${ACTORS_SESSION_SYNC_TIMEOUT:10000}"

View File

@ -15,6 +15,9 @@
*/ */
package org.thingsboard.server.common.msg.core; package org.thingsboard.server.common.msg.core;
import lombok.Data;
import org.thingsboard.server.common.data.id.SessionId;
import org.thingsboard.server.common.msg.aware.SessionAwareMsg;
import org.thingsboard.server.common.msg.session.FromDeviceMsg; import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
@ -22,7 +25,9 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
/** /**
* @author Andrew Shvayka * @author Andrew Shvayka
*/ */
@Data
public class SessionOpenMsg implements FromDeviceMsg { public class SessionOpenMsg implements FromDeviceMsg {
@Override @Override
public SessionMsgType getMsgType() { public SessionMsgType getMsgType() {
return SessionMsgType.SESSION_OPEN; return SessionMsgType.SESSION_OPEN;

View File

@ -29,7 +29,9 @@ import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.security.DeviceTokenCredentials; import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
import org.thingsboard.server.common.data.security.DeviceX509Credentials; import org.thingsboard.server.common.data.security.DeviceX509Credentials;
import org.thingsboard.server.common.msg.core.SessionOpenMsg;
import org.thingsboard.server.common.msg.session.AdaptorToSessionActorMsg; import org.thingsboard.server.common.msg.session.AdaptorToSessionActorMsg;
import org.thingsboard.server.common.msg.session.BasicAdaptorToSessionActorMsg;
import org.thingsboard.server.common.msg.session.BasicTransportToDeviceSessionActorMsg; import org.thingsboard.server.common.msg.session.BasicTransportToDeviceSessionActorMsg;
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg;
import org.thingsboard.server.common.transport.SessionMsgProcessor; import org.thingsboard.server.common.transport.SessionMsgProcessor;
@ -95,6 +97,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
log.trace("[{}] Processing msg: {}", sessionId, msg); log.trace("[{}] Processing msg: {}", sessionId, msg);
if (msg instanceof MqttMessage) { if (msg instanceof MqttMessage) {
processMqttMsg(ctx, (MqttMessage) msg); processMqttMsg(ctx, (MqttMessage) msg);
} else {
ctx.close();
} }
} }
@ -303,6 +307,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
} else { } else {
ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED)); ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED));
connected = true; connected = true;
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(),
new BasicAdaptorToSessionActorMsg(deviceSessionCtx, new SessionOpenMsg())));
checkGatewaySession(); checkGatewaySession();
} }
} }
@ -314,6 +320,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
if (deviceSessionCtx.login(new DeviceX509Credentials(sha3Hash))) { if (deviceSessionCtx.login(new DeviceX509Credentials(sha3Hash))) {
ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED)); ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED));
connected = true; connected = true;
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(),
new BasicAdaptorToSessionActorMsg(deviceSessionCtx, new SessionOpenMsg())));
checkGatewaySession(); checkGatewaySession();
} else { } else {
ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED)); ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED));