Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conference timeout and termination API - Restcomm 1171 #2617

Merged
merged 41 commits into from
Nov 30, 2017

Conversation

maria-farooq
Copy link

@maria-farooq maria-farooq commented Nov 7, 2017

related issues:
https://telestax.atlassian.net/browse/RESTCOMM-1171
https://telestax.atlassian.net/browse/RESTCOMM-758

@@ -58,12 +68,21 @@ private CustomHttpClientBuilder() {
}

private static CloseableHttpClient defaultClient = null;
private static CloseableHttpAsyncClient closeableHttpAsyncClient = null;
Copy link
Contributor

@jaimecasero jaimecasero Nov 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure putting sync and async factory in same class is meaningful (maybe a separated async factory would have work better). Lets keep it like this by now, since we are reuding the lifecycle, and final closing during app shutdown...

if (sender != null && !sender.isTerminated()) {
sender.tell(response, self());
} else {
if (logger.isInfoEnabled()) {
Copy link
Contributor

@jaimecasero jaimecasero Nov 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if we send msg to terminated actor? checking actor state from the outside is not guaranteed,as in the next instruction the state may have changed. So, there will be chances where we send the response,and the actor is terminated. Not sure is worth to make the distinction here, or maybe send response blindly to actor, and let Akka figure out what to do (deadletter box..)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree with letting akka handle the delivery dynamics

if (contentType != null) {
builder.setContentType(contentType.getValue());
}
builder.setContent(StringUtils.toString(stream));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont like how response is stringified here, i think it should be original "sender" responsability to do this if appropiate. I can see the existing HttpResponseDescriptor already expectsa String content, but i think its a bit dangerous in terms of encoding(this is assuming body is JVM charset encoded/UTF8...) and performance(we loss any streaming chance, and we create an String in memory with potentially big body with no control on actual length)

not sure worth the refactoring, but very worrying...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we refactor this as part of this PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will impact Downloader as well,so I guess we can do that later...

if(logger.isDebugEnabled())
logger.debug(String.format("Conference cdr is null for sid: %s", sid));
}else{
return DateTime.now().getMillis()-cdr.getDateCreated().getMillis();
Copy link
Contributor

@jaimecasero jaimecasero Nov 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we assume all JVM/OS nodes in the cluster are clock synced? are the nodes configured to sync system clock from a central server regularly?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaimecasero Network Time Protocol (NTP) is configured by default on Amazon Linux instances and for cloud service is up and running to make it synchronised to NTP server.


String conferenceSid = getConferenceSid(confRoom1);
assertEquals(2, getParticipantsSize(conferenceSid));
int liveCalls = MonitoringServiceTool.getInstance().getStatistics(deploymentUrl.toString(), adminAccountSid, adminAuthToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it worthit to depend test result on monitorignService? i expect monitoring service to collect on some collection frequency, will the test be stable if we include this assertion here?.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo monitoring service is a nice way to check live calls in memory, not sure why test would be unstable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I though monitoringService was getting stats from other components from time to time. Apparently components push data into monitoring service in real time instead. So i guess its safe to use the MonService during test... nevermind my comment

}

private int getActiveConferencesSize() {
JsonObject conferences = RestcommConferenceTool.getInstance().getConferences(deploymentUrl.toString(),adminAccountSid, adminAuthToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this may reuse my new countByFilter metthod :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaimecasero can you explain how can i use a dao method at this level, is there an api available on top of that ?

bobCall.listenForDisconnect();
georgeCall.listenForDisconnect();

assertTrue(bobCall.waitForDisconnect(80 * 1000));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess this depends on conf timeout, where is the conf timeout configured here? i guess the default 4hours is not good for testing. is this configured at rcml level for this tetscase?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaimecasero its not 4 hours for testing, its 60 seconds for testing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where are those 60 seconds configured?

Copy link
Author

@maria-farooq maria-farooq Nov 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in restcomm-conference.xml aka restcomm.xml for this specific test class

// Bob is a simple SIP Client. Will not register with Restcomm
private SipStack bobSipStack;
private SipPhone bobPhone;
private String bobContact = "sip:bob@127.0.0.1:5090";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make this test follow paralle testing approach?

Copy link
Author

@maria-farooq maria-farooq Nov 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

letme change

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -331,6 +331,9 @@ private AuthOutcome secureLevelControl(Account operatedAccount, String resourceA
String operatedAccountSid = null;
if (operatedAccount != null)
operatedAccountSid = operatedAccount.getSid().toString();
if (isSuperAdmin()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this affect to other existing operations? Seems like a big change.... Of course this means is the superAdmin anyway, but just wanted to check if this will change anything for other existing RESTAPI operations...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change would mean that superadmin account would have control over restcomm APIs (number, clients, call, conference etc) regardless of the fact that resource being owned by another account in the system

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq but there is already a method for this org.restcomm.connect.http.SecuredEndpoint#isSuperAdmin and can be used from any endpoint its needed.

I think if we go with this patch then we mess the SecuredEndpoints and the rules to follow and it will be harder to debug later.

I think we should remove this and instead check with isSuperAdmin method

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvagenas good point, i added this check for superadmin in conference and call endpoints intead

logger.info(String.format("updateConference accountsid: %s conferenceSid: %s", accountSid, sid));
Account account = daoManager.getAccountsDao().getAccount(accountSid);
try {
secure(account, "RestComm:Read:Conferences");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the correct literal "RestComm:Read:Conferences"? i dont know the convention, but this is not a ReadOnly operation, here we are modifying the conference, shouldnt be somethign like "Restcomm:Write:Conferences"?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch, updated

Copy link
Contributor

@jaimecasero jaimecasero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me know your opinion on comments

@gvagenas gvagenas changed the title Restcomm 1171 Conference timeout and termination API - Restcomm 1171 Nov 9, 2017
Copy link
Contributor

@gvagenas gvagenas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq I provided my comments and one of the most important is that the CallApiClient actor is a top-level actor and as far as I can see this actors will never get destroyed unless the Akka system stops.

Also, using LCM from Restcomm to Restcomm inside the cluster is very bad and restrictive design to my point of view, but this is not related to the patch here but rather to the old design decisions that were taken.

final String status = data.getFirst("Status");

if(status != null){
if(status.equalsIgnoreCase("completed")){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq I think we need to provide a default response in the case where the provided status DOESN NOT match the completed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

private void kickoutAllActiveParticipants(ConferenceDetailRecord conferenceDetailRecord){
List<CallDetailRecord> callDetailRecords = daoManager.getCallDetailRecordsDao().getRunningCallDetailRecordsByConferenceSid(conferenceDetailRecord.getSid());

if(callDetailRecords == null || callDetailRecords.isEmpty()){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq also here I think we need a response to tell user that there were no participants

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvagenas I dont think it need other than a suceesful response, user will get conference resource in response.
this case here is just to make sure in a race case when participants leave themselves before system kick them out

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main issue with any single response is that this would require to wait for result on async actions started from here, and which may take time (LVM remote invocation). The response should be succesful if the action of terminating the conf may be initiated.

I think any client can check the RESTAPI later to see how many participants are left at any moment...

return new CallApiClient(sid, daoManager);
}
});
return system.actorOf(props);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq here you create a top-level actor with a parent the system itself.

Nowhere in the patch, you destroy this actor, thus this actor and its child actors HttpAsycClientHelper will stay in memory for as long as the akka system is up and running.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq I believe better design would be to use ASK pattern, delegate the task to CallManager which create CallApiClient , use to kill the calls and then destroy the actor.

On top, we can use ASK pattern without blocking, just fire the request and return, since we don't need the response.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq also delegating the task to CallManager, we can save some LCM (http) requests.

CallManager can check which of the CDRs are local calls or not and either use update call method or LCM.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq I see the local calls are removed by the Conferences endpoint (Evicting private class) but still I think the task to remove remote calls actors should be delegated to CallManager that will create CallApiClient actors and then destroy them

logger.info("Call api response succeeded " + response.succeeded());
logger.info("Call api response: " + response);
}
requestee.tell(message, self);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq with the current implementation the requestee will always be null.
Shouldn't we protect the code for this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please chek comments below

}

protected void onHangup(Hangup message, ActorRef self, ActorRef sender) throws URISyntaxException, ParseException {
requestee = sender;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq What is the reason behind this? Any plans to use the CallApiClient in other places where we will need to return back the response, because currently there is no use of that

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have changed both CallApiClient and ConferenceApiClient to be disposable (used for one time request), they will clean them selves after sending back DownloaderResponse

}

@Override
public void postStop () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq as far as I can see, CallApiClient will never be destroyed and thus this method will never be called, see my comments on ConferencesEndpoint

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have changed both CallApiClient and ConferenceApiClient to be disposable (used for one time request), they will clean them selves after sending back DownloaderResponse

}
}

private String getSuperAdminAuthenticationHeader(){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq since the ConferencesEndpoint.updateConference() can be used by any account with RestComm:Modify:Conferences permision, why we create LCM using super admin credentials?
I think we should use the credentials of the account that requested the update initially

}
}

private String getSuperAdminAuthenticationHeader(){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq I think we should use the credentials of the account that requested the stop conference initially and not the super admin.

+ "At the postStop() method.");
}
if(conferenceApiClient != null && !conferenceApiClient.isTerminated())
getContext().stop(conferenceApiClient);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq instead of waiting for the Conference actor to get destroyed in order to destroy the conferenceApiClient, we can make use of the fact the ConferenceApiClient will send the DownloaderResponse to the Confernece actor and kill the actor at this point

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvagenas i have changed both CallApiClient and ConferenceApiClient to be disposable (used for one time request), they will clean them selves after sending back DownloaderResponse

@@ -331,6 +331,9 @@ private AuthOutcome secureLevelControl(Account operatedAccount, String resourceA
String operatedAccountSid = null;
if (operatedAccount != null)
operatedAccountSid = operatedAccount.getSid().toString();
if (isSuperAdmin()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq but there is already a method for this org.restcomm.connect.http.SecuredEndpoint#isSuperAdmin and can be used from any endpoint its needed.

I think if we go with this patch then we mess the SecuredEndpoints and the rules to follow and it will be harder to debug later.

I think we should remove this and instead check with isSuperAdmin method

Maria Farooq added 11 commits November 10, 2017 10:10
* master:
  fixed counter increase
  created notice in doc to alert about SMPP regex disable
  added test for new RegexRemover
  restore previous number selection,and disable regexes for smpp
  allow usage for nonSIP scenarios
  use organizationutil to match incomingphonenumber.
  make test more stable by preventing conunt of data from previous testcase
  Fixed #2625: Update Quick Start documentation for Android BETA7
  removed listPhones from dao attributes, DAO needs to be stateless.
  fixed toString method to show fields
  fixed sip and tomcat as test dependencies in parent.defined proper dependencies at child level.
  Patch to fix Record race condition. Also provides enhancements for MockMediaGateway. This close #RESTCOMM-1219 This close #RESTCOMM-1229 This close #RESTCOMM-1230 This close #RESTCOMM-1231
  Work in progress This refer to #RESTCOMM-1219
  Patch for MockMediaGateway to create recording file on RQNT ES (sg=pr) request This refer to #RESTCOMM-1219
  Work in progress This refer to #RESTCOMM-1219
  Patch for MockMediaGateway to create recording file on RQNT ES (sg=pr) request This refer to #RESTCOMM-1219
  Patch for MockMediaGateway to create recording file on RQNT ES (sg=pr) request This refer to #RESTCOMM-1219
  Work in progress This refer to #RESTCOMM-1219
  Work in progress This refer to #RESTCOMM-1219
  Work in progress This refer to #RESTCOMM-1219
Copy link
Contributor

@gvagenas gvagenas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq please check my comments, I think there few things to improve.
There are some comments related to the local and remote call actors, that I am not sure are correct, lets discuss about them

@@ -309,8 +326,10 @@ public void execute(Object message) throws Exception {
final Leave leave = new Leave();
call.tell(leave, super.source);
}
//tell conference api client to call conference api to terminate conference and kick all calls
conferenceApiClient = conferenceApiClient();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq Is there a way to tell if a conference has remote participants or not? This would be a great improvement in order to save resources by not creating and executing the ConferenceApiClient

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can check by DB but that is like alternative to me not an optimisation, in most cases it would be an overhead query

if(message.getCallDetailRecord().getInstanceId().equals(RestcommConfiguration.getInstance().getMain().getInstanceId())){
ActorRef callTobeHangup = lookup(new GetCall(message.getCallDetailRecord().getCallPath()));
if (callTobeHangup != null){
callTobeHangup.tell(message, self);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq at the Conference.onStopConference() method, the Conference actor will ask all local call actors to leave.
The call actor at this point will send BYE to the sip client.
So there is no need to send Hangup to the local call actors.

Important! I think there is a bug in the call actor where after Leave message is received, the call actor will never get destroyed.
As far as I can see, when the call actor receives Leavemessage:

  1. Will send bye
  2. Will tell MmsCallController to leave (destroy media resources)
    Possible BUG -> 3. The Call.onMediaServerControllerStateChanged doesn't take care of the MmsCallController response while state is Leaving
    We need to investigate this one

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvagenas do you think this is part of the scop of this PR? this bug is there regardless if we merge this patch or not no? can we handle that seperatly

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq do you think this is part of the scop of this PR? the bug is not in the scope of this PR but I believe CallManager shouldn't try to Hangup local calls.

if (logger.isInfoEnabled()) {
logger.info("Conference Received Timeout, will stop conference now.");
}
onStopConference(new StopConference(SUPER_ADMIN_ACCOUNT_SID), self, sender);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq Maybe we should differentiate the StopConference initiated by SuperAdmin and the one initiated by the timer. This is just an idea, not sure about the implementation but I think if it sounds feasible to you we should investigate it

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can provide a reason field in StopConference as well in API, in case of timeout its will be conference time limit reached this field will later be passed as reason header in corresponding BYE to sip clients

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq sounds good

logger.warning(String.format("could not retrive any conference record for this conference accountSid %s name: %s", accountSid, name));
return null;
}else{
return conferenceDetailRecords.get(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq isn't this dangerous since we pick the first available Conference in the DB? I believe we should stop and fail the request when conferenceSid is null.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conferenceSid is not always available at local conference we care about accountSid:name

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq but still picking up the first on the list its dangerous since this one might not be the conference we are looking for

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvagenas as per our conference design/state, there is only one conference in DB in running state.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq ??? Only one conference in running state? I am missing something here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will be only 1 RUNNING Conference for AccountSid and given Name
Conference ID is unique because AccountSid+ConferenceName is unique

} else {
try {
URI uri = new URI("/restcomm"+conferenceDetailRecord.getUri());
uri = UriUtils.resolve(uri);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq here we rely on the fact that the cluster has a common public IP address (the LB public IP). Nothing bad in the current phase but maybe the conferenceDetailRecord.getUri() should contain the remote IP Address (when/if the conference is remote).
This would help later to have conferences between instances that don't belong to the same "cluster".
This is just an idea for discussion.

Account account = daoManager.getAccountsDao().getAccount(accountSid);
Account effectiveAccount = userIdentityContext.getEffectiveAccount();
try {
secure(account, "RestComm:Modify:Conferences");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq Since later we use isSuperAdmin() I don't think we need to check permissions here.
The updateConference() method could be protected with just the isSuperAdmin()

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conference termination request can be initiated by owner of the conference as well hence we need to make sure that resource is being accessed by proper account

//allow super admin to perform update on any conference - https://telestax.atlassian.net/browse/RESTCOMM-1171
if (!isSuperAdmin()) {
try {
secure(account, cdr.getAccountSid(), SecuredType.SECURED_STANDARD);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq can you elaborate on that? Why we use secure again here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conference termination request can be initiated by owner of the conference as well hence we need to make sure that resource is being accessed by proper account

final String status = data.getFirst("Status");

if(status != null){
if (status.equalsIgnoreCase("completed")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq you can combine status != null AND status.equalsIgnoreCase("completed") in the same if statement so we don't need duplicate else clause that does exactly the same thing

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, changed

while(iterator.hasNext()){
final CallDetailRecord CallDR = iterator.next();
if (callManager == null)
callManager = (ActorRef) context.getAttribute("org.restcomm.connect.telephony.CallManager");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq why don't you retrieve the CallManager actor outside the while statement so you do it just once and not for every CDR in the list?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point

final CallDetailRecord CallDR = iterator.next();
if (callManager == null)
callManager = (ActorRef) context.getAttribute("org.restcomm.connect.telephony.CallManager");
callManager.tell(new Hangup("Conference Terminated", effectiveAccount.getSid(), CallDR), null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq Does it worth to create a new message instead of use Hangup that is used by VoiceInterpreter to ask the Call actor to terminate the call?
Not important, just wondering if it would be a better approach to have a new message here

@gvagenas
Copy link
Contributor

gvagenas commented Nov 14, 2017

@maria-farooq I am not comfortable with the current implementation because I can see redundant functionality and not a clear separation of concerns in the actors/endpoints involved. Let me elaborate:

  • The feature here is about how to terminate a Conference and remove all call actors.
  • The conference termination might be initiated because of a timer or because of a user action (REST API)
  • Call actors might be either local actors or remote actors.
  • Local actors should be removed using Akka messaging (send Leave message)
  • Remote actors should be removed using LCM

Currently, your patch implements the following:

  1. On timer timeout Conference actor moves to Evicting state where a) asks Local actors to Leave b) creates a ConferenceApiClient actor and send to it the StopConference message
  2. The ConferenceApiClient will then create a REST API request for the ConferencesEndpoint to update Conference.
  3. The ConferencesEndpoint will ask CallManager to Hangup all calls found in the CDR table related to the given Conference
  4. CallManager will first try to remove local calls and then will try to remove local calls using CallsApiClient
  5. CallApiClient will create an LCM REST API request to CallsEndpoint to complete the remote call

My comments on the above implementation:

  1. When Conference actor reach the Evicting state, should be self-sufficient and a) remove local call actor b) check DB and remove remote call actors using LCM
  2. In both timeout and user-initiated StopConfernece, Conference actor should be responsible to move FSM state to Evicting and thus remove local and remote call actors
  3. There is no reason for the CallManager to attempt to clean up local call actors since given the above steps, we know that Conference actor cleaned up already the local call actors, and will initiate LCM for the remote actors
  4. The ConferenceApiClient is redundant in that case, it shouldn't be used
  5. On user-initiated StopConference the ConferencesEndpoint should not try to kick out any participant, this endpoint role is not to deal with participants and calls. The ConferencesEndpoint should only try to update the state of the Conference to Evicting by sending StopConference to either the local or remote Conference actor (akka messaging or LCM)
  6. This way, we don't have duplicate functionality where ConferencesEndpoint kicks out participants, its the responsibility of Conference actor to kick out call actors
  7. Thus CallApiClient is also redundant here
  8. LCM needs to be enhanced in order to:
    • When we complete a call actor because Conference stopped, we need the proper Header in the Bye request
    • Be able to reach remote Conference actors and send to them StopConference

Maria Farooq added 4 commits November 15, 2017 12:21
* master:
  Updated quick start for beta.5.
  added unstable beased on latest test results from CI
  LiveCallModificationTest modified to test LiveCall and Mgcp metrics This refer to #RESTCOMM-1238
  fixes subsequent regex removal
  includign category to exclude unstable tests
…incharge of removing local and remote participants
Copy link
Contributor

@gvagenas gvagenas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq see my comments for a minor issue that I think should be fixed.
Other than that looks good

@@ -95,6 +108,8 @@
private Sid sid;
private final List<ActorRef> calls;
private final List<ActorRef> observers;
//list of callApiClients created by Conference
private List<ActorRef> callApiClients;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq There is no need to keep a list of CallApiClients, this is redundant and will consume memory for no reason. See my comment later for the onDownloaderResponse method

private void onDownloaderResponse(DownloaderResponse message, ActorRef self, ActorRef sender) {
//make sure we only remove sender that is callApiClient and was created by this conference actor
//so we don't kill a sender that has accidently broadcast a DownloaderResponse to this conference.
if(callApiClients.contains(sender)){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maria-farooq as said earlier no need to keep a list of CallApiClient and then check if sender is on the list.
I believe we should stop sender straight away UNLESS if there is a chance to receive DownloaderResponse from other actors, which I cannot think of such a case.

Even if that's the case (other actors sends DownloaderResponse to Conference) maybe its better to create another wrapper message for the responses of CallApiClient

@maria-farooq
Copy link
Author

@gvagenas created a new wrapper for callapiresponse instead of reusing downloader response.

@maria-farooq maria-farooq merged commit 4e8dfe2 into master Nov 30, 2017
@jaimecasero jaimecasero deleted the RESTCOMM-1171 branch April 11, 2018 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants