RO Server (Delphi) prevents program from exiting (hangs)

delphi

(marcantheunis) #1

It seems our RO server can hang indefinately sometimes upon application exit.
From the call stack I am inclined to believe it is related to the RO (callback) events
Could this be te case? Can this be avoided?
RO version 9.4.107.1363

One thread is in the TROSCServerWorker.WaitForEventsAndMethods loop
while the main thread is in the while loop in TROSynapseServerSocket.Destroy

TIA,
Frederic


(DonaldShimoda) #2

Do you try unscribing to events before destroy app?


(marcantheunis) #3

Which un(sub?)scribe are you talking about.
Of which class is this a member function?
FYI: I am talking about the RO server application, the client is not closed, it keeps running.
I do not call any subscribe or unsubscribe in that application

Events are handled by a decendent class of IROEventWriter which get generated by the RODL
var
RobotEvntswriter : IRobotEvents2_Writer;

if supports (dmGlobal.InMemoryEventRepository, IRobotEvents2_Writer,RobotEvntswriter) then
RobotEvntswriter.OnSendMessage(EmptyGUID,Dialog.ID,response,True);

Note: I have a very high
InMemorySessionManager.SessionDuration (several days)
could that be related?


(EvgenyK) #4

what event mode you are using ?
legacy, when events are registered from client-side or .NET compatible, when events are registered on server-side?


(marcantheunis) #5

On the client side I have
FEventReceiver.LegacyEvents:=False;
It looks to me like events are registered on the client side (was that the question?)

Client code snippet 1:
FEventReceiver:=TROEventReceiver.Create(Self);
FEventReceiver.Channel:=ROSuperTCPChannel;
FEventReceiver.Interval:=300;
FEventReceiver.Message:=BinMessage_ER; // FVC: Not sure if we need a separate BinMessage
FEventReceiver.LegacyEvents:=False;
FEventReceiver.ServiceName:=‘RobotService2’;
FEventReceiver.OnPollException:=EventReceiverPollException;
FEventReceiver.OnActivate:=EventReceiverActivate;
FEventReceiver.OnDeactivate:=EventReceiverDeactivate;

Client code snippet 2:
// Register the event handlers
dmGlobalRobot.EventReceiver.RegisterEventHandlers(
[EID_RobotEvents2, EID_RobotServerEvents2],
[Self, Self]);
// Starts polling
dmGlobalRobot.EventReceiver.Active := TRUE;


(EvgenyK) #6
FEventReceiver.LegacyEvents:=False;

it means that you are using .NET compatible events. as a result, these events should be registered on server-side, say in login method


(marcantheunis) #7

Can you tell me which class and which function?
Looking for register on docs.remotingsdk.com does not give me any applicable information it seems
Is there sample code?
I don’t find register functions in RemObjects SDK for Delphi\SuperTCP Channel Chat


(EvgenyK) #8

see Login method in the SuperTCP Channel Chat sample:

RegisterEventClient(GuidToString(Session.SessionID), EID_ChatEvents);

and in Logout:

UnregisterEventClient(GUIDToString(ClientID), EID_ChatEvents);

(marcantheunis) #9

hmm, for now this does not fix the issue.
To be clear: My clients are still running so the logout is not called yet.
Should it work then?

I will check if the Login gets called first and for all clients.
However in my case after a server restart an existing client will not re-login but it will reconnect.
I guess that will give me the same hang issue then.
Is the InMemoryEventRepositoryAfterAddSession event not a better place to register?

FYI: Code below gets called before any other function (or event) on the server side:

function TRobotService2.Login(const aUserID: String): String;
var
newuser : TUserInfo;
RobotEvntswriter : IRobotEvents2_Writer;
begin
{ Checks if the user is already logged in }
if (fUsers.Search(‘UserID’, aUserID) <> NIL) then
raise Exception.CreateFmt(‘Client %s is already logged in’ +
#13’Select an other ClientID’, [aUserID]);

{ Adds the user to the internal list of logged users }
newuser := fUsers.Add;
newuser.UserID := aUserID;
newuser.SessionID := GUIDToString(Session.SessionID);

{ Stores the UserID of the user in the session.
This will be used in the OnLogout and OnSendMessage methods }
Session.Values[‘UserID’] := aUserID;
result := newuser.SessionID;

RegisterEventClient(GuidToString(Session.SessionID), EID_RobotServerEvents2);
RegisterEventClient(GuidToString(Session.SessionID), EID_RobotEvents2);

try
if supports (EventRepository, IRobotEvents2_Writer, RobotEvntswriter) then
begin
RobotEvntswriter.SessionList.CommaText := result;
{ Only broadcasts to the session listed in SessionList }
RobotEvntswriter.ExcludeSessionList := FALSE;
{ Generates the OnLogin event }
RobotEvntswriter.OnLogin(EmptyGUID, newuser);
end;
finally
RobotEvntswriter := nil;
end;

{ Instructs the framework not to destroy the object }
RetainObject(newuser);
end;


(EvgenyK) #10

what SessionManager and EventRepository you are using? Olympia, InMemory, RODB or DADB ?


(marcantheunis) #11
InMemorySessionManager: TROInMemorySessionManager;
InMemoryEventRepository: TROInMemoryEventRepository;

(EvgenyK) #12

something is wrong with your server then.
can you check, that all your _impl, except login one have requireSession=True?
InMemory Session manager supposes that all data is stored in memory and after restarting server, all clients should re-login otherwise SessionNotFound exception should be raised at calling of any method of non-login service


(marcantheunis) #13

Ach, I only have a single service, it is requiresSession=False
So I need to put the login into a seperate RO service, correct?


(EvgenyK) #14

yep, only login service should have requiresSession=False.
all others services should have requiresSession=True.


(DonaldShimoda) #15

Evgeny solve your doubts.

HTH.


(marcantheunis) #16

FYI EvgenyK e.a.:
My server was calling the RO interface from the application itself.
These calls happened without a login.
Is a login (registereventclient) also necessary for the server itself?

Question: What is the behaviour when a call is made without a session?
It looks like the QueryInterface on the THYLocalService object returns nil, correct?
supports (_RobotService, IRobotService2, intf) => nil


(EvgenyK) #17

in some cases, it is enough to create service instance manually and later destroy it, like

  myservice := TNewService.Create(nil);
  try
    myservice.mymethod;
  finally
     myservice.Free;
  end;

(marcantheunis) #18

OK, thanks, for now I use THYLocalService and log in.

My problem is not resolved however.
The RO server still hangs upon exit.
FYI: the RO server is also a RO client and a Hydra plugin host, could you pinpoint the issue better if I send you callstacks?

Note: reconnecting a client after a RO server restart also does not work anymore now.
I get the error below in my RO client (TUserInfo is a RODL class I use)
Error reading parameter aUserInfo: Unexpected class found in stream; class “TUserInfo” does not descend from “TUserInfo”.


(EvgenyK) #19

yes, you can send callstack.

this error means that you should put _Intf where is TUserInfo declared into shared run-time package used by host and plugin