mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server: Session closingLock from .lock() to .tryLock()
parent
cd1aad4eff
commit
7636d8a516
|
@ -28,6 +28,7 @@ import java.util.TimerTask;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
@ -447,7 +448,8 @@ public abstract class SessionManager {
|
||||||
long sessionExistsSince = currentMillis - sessionNotActive.getStartTime();
|
long sessionExistsSince = currentMillis - sessionNotActive.getStartTime();
|
||||||
if (sessionExistsSince > (openviduConfig.getSessionGarbageThreshold() * 1000)) {
|
if (sessionExistsSince > (openviduConfig.getSessionGarbageThreshold() * 1000)) {
|
||||||
try {
|
try {
|
||||||
sessionNotActive.closingLock.writeLock().lock();
|
if (sessionNotActive.closingLock.writeLock().tryLock(15, TimeUnit.SECONDS)) {
|
||||||
|
try {
|
||||||
if (sessions.containsKey(sessionId)) {
|
if (sessions.containsKey(sessionId)) {
|
||||||
// The session passed to active during lock wait
|
// The session passed to active during lock wait
|
||||||
continue;
|
continue;
|
||||||
|
@ -458,6 +460,16 @@ public abstract class SessionManager {
|
||||||
} finally {
|
} finally {
|
||||||
sessionNotActive.closingLock.writeLock().unlock();
|
sessionNotActive.closingLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.error(
|
||||||
|
"Timeout waiting for Session closing lock to be available for garbage collector to clean session {}",
|
||||||
|
sessionId);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error(
|
||||||
|
"InterruptedException while waiting for Session closing lock to be available for garbage collector to clean session {}",
|
||||||
|
sessionId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +527,8 @@ public abstract class SessionManager {
|
||||||
// to the session. That is: if the session was in the automatic recording stop
|
// to the session. That is: if the session was in the automatic recording stop
|
||||||
// timeout with INDIVIDUAL recording (no docker participant connected)
|
// timeout with INDIVIDUAL recording (no docker participant connected)
|
||||||
try {
|
try {
|
||||||
session.closingLock.writeLock().lock();
|
if (session.closingLock.writeLock().tryLock(15, TimeUnit.SECONDS)) {
|
||||||
|
try {
|
||||||
if (session.isClosed()) {
|
if (session.isClosed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -523,6 +536,12 @@ public abstract class SessionManager {
|
||||||
} finally {
|
} finally {
|
||||||
session.closingLock.writeLock().unlock();
|
session.closingLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.error("Timeout waiting for Session {} closing lock to be available", sessionId);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("InterruptedException while waiting for Session {} closing lock to be available", sessionId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -331,12 +331,18 @@ public class KurentoParticipant extends Participant {
|
||||||
} finally {
|
} finally {
|
||||||
pub.closingLock.writeLock().unlock();
|
pub.closingLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.error(
|
||||||
|
"Timeout waiting for PublisherEndpoint closing lock of participant {} to be available for participant {} to call cancelReceveivingMedia",
|
||||||
|
senderName, this.getParticipantPublicId());
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
subscribers.remove(senderName);
|
|
||||||
log.error(
|
log.error(
|
||||||
"Timeout wating for PublisherEndpoint closing lock of participant {} to be available for participant {} to call cancelReceveivingMedia",
|
"InterruptedException while waiting for PublisherEndpoint closing lock of participant {} to be available for participant {} to call cancelReceveivingMedia",
|
||||||
senderName, this.getParticipantPublicId());
|
senderName, this.getParticipantPublicId());
|
||||||
|
} finally {
|
||||||
|
// Always clean map
|
||||||
|
subscribers.remove(senderName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
/* Protected by Session.closingLock.readLock */
|
/* Protected by Session.closingLock.readLock */
|
||||||
public synchronized void joinRoom(Participant participant, String sessionId, Integer transactionId) {
|
public void joinRoom(Participant participant, String sessionId, Integer transactionId) {
|
||||||
Set<Participant> existingParticipants = null;
|
Set<Participant> existingParticipants = null;
|
||||||
boolean lockAcquired = false;
|
boolean lockAcquired = false;
|
||||||
try {
|
try {
|
||||||
|
@ -162,8 +162,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean leaveRoom(Participant participant, Integer transactionId, EndReason reason,
|
public boolean leaveRoom(Participant participant, Integer transactionId, EndReason reason, boolean closeWebSocket) {
|
||||||
boolean closeWebSocket) {
|
|
||||||
log.info("Request [LEAVE_ROOM] for participant {} of session {} with reason {}",
|
log.info("Request [LEAVE_ROOM] for participant {} of session {} with reason {}",
|
||||||
participant.getParticipantPublicId(), participant.getSessionId(),
|
participant.getParticipantPublicId(), participant.getSessionId(),
|
||||||
reason != null ? reason.name() : "NULL");
|
reason != null ? reason.name() : "NULL");
|
||||||
|
@ -235,7 +234,8 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
recordingManager.initAutomaticRecordingStopThread(session);
|
recordingManager.initAutomaticRecordingStopThread(session);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
session.closingLock.writeLock().lock();
|
if (session.closingLock.writeLock().tryLock(15, TimeUnit.SECONDS)) {
|
||||||
|
try {
|
||||||
if (session.isClosed()) {
|
if (session.isClosed()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,16 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
} finally {
|
} finally {
|
||||||
session.closingLock.writeLock().unlock();
|
session.closingLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.error(
|
||||||
|
"Timeout waiting for Session {} closing lock to be available for closing as last participant left",
|
||||||
|
sessionId);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error(
|
||||||
|
"InterruptedException while waiting for Session {} closing lock to be available for closing as last participant left",
|
||||||
|
sessionId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (remainingParticipants.size() == 1 && openviduConfig.isRecordingModuleEnabled()
|
} else if (remainingParticipants.size() == 1 && openviduConfig.isRecordingModuleEnabled()
|
||||||
&& MediaMode.ROUTED.equals(session.getSessionProperties().mediaMode())
|
&& MediaMode.ROUTED.equals(session.getSessionProperties().mediaMode())
|
||||||
|
|
|
@ -480,23 +480,24 @@ public class RecordingManager {
|
||||||
recordingId, this.openviduConfig.getOpenviduRecordingAutostopTimeout());
|
recordingId, this.openviduConfig.getOpenviduRecordingAutostopTimeout());
|
||||||
|
|
||||||
if (this.automaticRecordingStopThreads.remove(session.getSessionId()) != null) {
|
if (this.automaticRecordingStopThreads.remove(session.getSessionId()) != null) {
|
||||||
|
|
||||||
boolean alreadyUnlocked = false;
|
boolean alreadyUnlocked = false;
|
||||||
try {
|
try {
|
||||||
session.closingLock.writeLock().lock();
|
if (session.closingLock.writeLock().tryLock(15, TimeUnit.SECONDS)) {
|
||||||
|
try {
|
||||||
if (session.isClosed()) {
|
if (session.isClosed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.getParticipants().size() == 0 || session.onlyRecorderParticipant()) {
|
if (session.getParticipants().size() == 0 || session.onlyRecorderParticipant()) {
|
||||||
// Close session if there are no participants connected (RECORDER does not
|
// Close session if there are no participants connected (RECORDER does not
|
||||||
// count) and publishing
|
// count) and publishing
|
||||||
log.info("Closing session {} after automatic stop of recording {}", session.getSessionId(),
|
log.info("Closing session {} after automatic stop of recording {}",
|
||||||
recordingId);
|
session.getSessionId(), recordingId);
|
||||||
sessionManager.closeSessionAndEmptyCollections(session, EndReason.automaticStop, true);
|
sessionManager.closeSessionAndEmptyCollections(session, EndReason.automaticStop,
|
||||||
|
true);
|
||||||
} else {
|
} else {
|
||||||
// There are users connected, but no one is publishing
|
// There are users connected, but no one is publishing
|
||||||
session.closingLock.writeLock().unlock(); // We don't need the lock if session's not closing
|
// We don't need the lock if session is not closing
|
||||||
|
session.closingLock.writeLock().unlock();
|
||||||
alreadyUnlocked = true;
|
alreadyUnlocked = true;
|
||||||
log.info(
|
log.info(
|
||||||
"Automatic stopping recording {}. There are users connected to session {}, but no one is publishing",
|
"Automatic stopping recording {}. There are users connected to session {}, but no one is publishing",
|
||||||
|
@ -508,6 +509,17 @@ public class RecordingManager {
|
||||||
session.closingLock.writeLock().unlock();
|
session.closingLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.error(
|
||||||
|
"Timeout waiting for Session {} closing lock to be available for automatic recording stop thred",
|
||||||
|
session.getSessionId());
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error(
|
||||||
|
"InterruptedException while waiting for Session {} closing lock to be available for automatic recording stop thred",
|
||||||
|
session.getSessionId());
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// This code shouldn't be reachable
|
// This code shouldn't be reachable
|
||||||
log.warn("Recording {} was already automatically stopped by a previous thread", recordingId);
|
log.warn("Recording {} was already automatically stopped by a previous thread", recordingId);
|
||||||
|
@ -523,7 +535,8 @@ public class RecordingManager {
|
||||||
if (future != null) {
|
if (future != null) {
|
||||||
boolean cancelled = future.cancel(false);
|
boolean cancelled = future.cancel(false);
|
||||||
try {
|
try {
|
||||||
session.closingLock.writeLock().lock();
|
if (session.closingLock.writeLock().tryLock(15, TimeUnit.SECONDS)) {
|
||||||
|
try {
|
||||||
if (session.isClosed()) {
|
if (session.isClosed()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -536,10 +549,20 @@ public class RecordingManager {
|
||||||
session.getSessionId());
|
session.getSessionId());
|
||||||
sessionManager.closeSessionAndEmptyCollections(session, reason, false);
|
sessionManager.closeSessionAndEmptyCollections(session, reason, false);
|
||||||
}
|
}
|
||||||
return cancelled;
|
|
||||||
} finally {
|
} finally {
|
||||||
session.closingLock.writeLock().unlock();
|
session.closingLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.error(
|
||||||
|
"Timeout waiting for Session {} closing lock to be available for aborting automatic recording stop thred",
|
||||||
|
session.getSessionId());
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error(
|
||||||
|
"InterruptedException while waiting for Session {} closing lock to be available for aborting automatic recording stop thred",
|
||||||
|
session.getSessionId());
|
||||||
|
}
|
||||||
|
return cancelled;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.net.MalformedURLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
@ -234,16 +235,29 @@ public class SessionRestController {
|
||||||
Session sessionNotActive = this.sessionManager.getSessionNotActive(sessionId);
|
Session sessionNotActive = this.sessionManager.getSessionNotActive(sessionId);
|
||||||
if (sessionNotActive != null) {
|
if (sessionNotActive != null) {
|
||||||
try {
|
try {
|
||||||
sessionNotActive.closingLock.writeLock().lock();
|
if (sessionNotActive.closingLock.writeLock().tryLock(15, TimeUnit.SECONDS)) {
|
||||||
|
try {
|
||||||
if (sessionNotActive.isClosed()) {
|
if (sessionNotActive.isClosed()) {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
this.sessionManager.closeSessionAndEmptyCollections(sessionNotActive, EndReason.sessionClosedByServer,
|
this.sessionManager.closeSessionAndEmptyCollections(sessionNotActive,
|
||||||
true);
|
EndReason.sessionClosedByServer, true);
|
||||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
} finally {
|
} finally {
|
||||||
sessionNotActive.closingLock.writeLock().unlock();
|
sessionNotActive.closingLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
String errorMsg = "Timeout waiting for Session " + sessionId
|
||||||
|
+ " closing lock to be available for closing from DELETE /api/sessions";
|
||||||
|
log.error(errorMsg);
|
||||||
|
return this.generateErrorResponse(errorMsg, "/api/sessions", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
String errorMsg = "InterruptedException while waiting for Session " + sessionId
|
||||||
|
+ " closing lock to be available for closing from DELETE /api/sessions";
|
||||||
|
log.error(errorMsg);
|
||||||
|
return this.generateErrorResponse(errorMsg, "/api/sessions", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue