Archived

This forum has been archived. Please start a new discussion on GitHub.

Glacier2: sessions vs callbacks

Hi,

I have some questions regarding Glacier2 sessions and client callbacks coexistence.
My flow is like following:

1. On some stage when my iPhone client moved to background, attempt to call client's callback object throws ObjectNotExistException.
According to Ice Manual (Glacier2 Session Management - Ice 3.4 - ZeroC):
In that case <if the server regularly calls back to the client>, Glacier2 will automatically destroy the session if a failure occurs while forwarding a server callback to the client
In my case session's destroy method is not called.
Please explain this behaviour.

2. Client app is resumed and would like to know whether its session is still alive. For this purpose it calls ice_ping on session object that throws ObjectNotExistException though the session is still alive. I'd expect something like ConnectionLostException, otherwise ice_ping should return normally. Please explain.

3. Now client tries to re-establish session. As stated in Manual (Glacier2 Session Management - Ice 3.4 - ZeroC):
The create operations may be called with information that identifies an existing session. For example, this can occur when a client loses its connection to the router but its previous session has not yet expired (and therefore the router has not yet invoked destroy on its Session proxy). A session manager implementation must be prepared to handle this situation.
What exactly SessionManager is expected to do? Should it call (it will be a nested call?) to previously saved SessionControlPrx destroy method, and after that create a new session?

My Environment:
Server: C# + ICE 3.4.2 on Windows (Vista, Server 2008)
Client: Ice Touch 1.2.0

Comments

  • benoit
    benoit Rennes, France
    Hi,
    allro wrote: »
    Hi,

    I have some questions regarding Glacier2 sessions and client callbacks coexistence.
    My flow is like following:

    1. On some stage when my iPhone client moved to background, attempt to call client's callback object throws ObjectNotExistException.
    According to Ice Manual (Glacier2 Session Management - Ice 3.4 - ZeroC):

    In my case session's destroy method is not called.
    Please explain this behaviour.

    2. Client app is resumed and would like to know whether its session is still alive. For this purpose it calls ice_ping on session object that throws ObjectNotExistException though the session is still alive. I'd expect something like ConnectionLostException, otherwise ice_ping should return normally. Please explain.

    The destroy method should be called if the session gets destroyed as a result of the failure of a server to client invocation and ice_ping on the session object shouldn't fail with Ice::ObjectNotExistException if the session is still alive. Did you try enabling some tracing on Glacier2 to investigate why it doesn't behave as expected? You can for instance enable the following properties:
    • Glacier2.Trace.Session=1
    • Glacier2.Trace.Client.Reject=1
    3. Now client tries to re-establish session. As stated in Manual (Glacier2 Session Management - Ice 3.4 - ZeroC):
    What exactly SessionManager is expected to do? Should it call (it will be a nested call?) to previously saved SessionControlPrx destroy method, and after that create a new session?

    Calling destroy on the session control object is useful to destroy an active session. If your session manager implementation already knows that the session was destroyed (the session destroy method was called), it doesn't need to call it.

    Cheers,
    Benoit.
  • Thanks for fast response.
    Unfortunately I still don't get it :confused:

    1.
    The destroy method should be called if the session gets destroyed as a result of the failure of a server to client invocation
    Glacier2 fails to invoke a method on client callback object with Ice.ObjectNotExistException exception. I assume that Glacier2 should destroy client's session and it doesn't happens. Is it expected behaviour?
    Or Glacier2 is supposed to destroy client's session on Ice.ConnectionLostException only?

    2.
    ice_ping on the session object shouldn't fail with Ice::ObjectNotExistException if the session is still alive
    It looks like ice_ping fails due to incorrect implementation of my SessionManager create method. It looks like:
    public override Glacier2.SessionPrx create(string userId, Glacier2.SessionControlPrx control, Ice.Current current__)
    { 
        Ice.Identity userSessionId = new Ice.Identity(userId, strSessionType);
        Ice.ObjectPrx prx = null;
        ...
    
        if (null == current__.adapter.find(userSessionId))
        {      
            prx = current__.adapter.add(new UserSessionI(userId), userSessionId);        
        }
        else // "existing session" case
        {
            prx = current__.adapter.createProxy(userSessionId);        
        }
    
        return Glacier2.SessionPrxHelper.uncheckedCast(prx);
    }
    
    Session's destroy looks pretty standard:
    public override void destroy(Ice.Current current__)
    {
    	trace("destroy called for userId=" + userId_);
    	...
    	current__.adapter.remove(current__.id);
    }
    
    Now, client creates a new session before previous one get expired. He receives a proxy to existing session servant and starts working normally until the servant will be destroyed by Glacier2 due to expiration of previous session.

    I've tried to change it as following:
    public override Glacier2.SessionPrx create(string userId, Glacier2.SessionControlPrx control, Ice.Current current__)
    {
    	Ice.Identity userSessionId = new Ice.Identity(userId, strSessionType);
    	Ice.ObjectPrx prx = null; 
    	if (null != current__.adapter.find(userSessionId)) // "existing session" case
    	{
    		trace("Existing session found for userId=" + userId);
    		Glacier2.SessionControlPrx currentControl = getSessionControl(userId);
    
    		currentControl.destroy();
    		trace("Existing session destroyed for userId=" + userId);
    	}
    
    	if (null == current__.adapter.find(userSessionId))
    	{
    		prx = current__.adapter.add(new UserSessionI(userId), userSessionId);
    		setSessionControl(userId, control); 
    		trace("New session created for userId=" + userId);
    
                    return Glacier2.SessionPrxHelper.uncheckedCast(prx);
    	}
    	else // "still existing session" case
    	{
    		trace("Cleanup failed for userId=" + userId);
    		return null;
    	}	
    }
    
    Unfortunately it doesn't work - though currentControl.destroy() is called I receive "Cleanup failed".
    What's wrong with this implementation?
    How "existing session" situation should be handled properly if Ice.Identity based on userId?
  • benoit
    benoit Rennes, France
    Hi Alex,

    An Ice::ObjectNotExistException doesn't necessarily indicate a communication failure with the client. It might just mean that the invocation failed because no servant was registered for the object identity from the proxy.

    The Glacier2::Session::destroy() method is called asynchronously when you call destroy() on the session control object. So when the destroy session control invocation returns, it doesn't necessarily mean that your session destroy method was called (yet). You'll need to add some synchronization if you really want to keep using the user ID for the session identity. Something like the above should work:
    // Session destroy method
    public override void destroy(Ice.Current current__)
    {
    	trace("destroy called for userId=" + userId_);
    	...
    	current__.adapter.remove(current__.id);
            sessionManager.sessionDestroyed();
    }
    
    // Session Manager 
    public void sessionDestroyed()
    {
         lock(this)
         {
             System.Threading.Monitor.PulseAll(this)   
         }
    };
    
    public override Glacier2.SessionPrx create(string userId, Glacier2.SessionControlPrx control, Ice.Current current__)
    {
    	Ice.Identity userSessionId = new Ice.Identity(userId, strSessionType);
    	Ice.ObjectPrx prx = null; 
    	if (null != current__.adapter.find(userSessionId)) // "existing session" case
    	{
    		trace("Existing session found for userId=" + userId);
    		Glacier2.SessionControlPrx currentControl = getSessionControl(userId);
    
    		currentControl.destroy();
    		trace("Existing session destroyed for userId=" + userId);
    
                    // Wait for Session.destroy() call
                    while(null != current__.adapter.find(userSessionId))
                    {
                          lock(this)
                          {
                               System.Threading.Monitor.Wait(this);
                          }
                    }
    	}
    
    
    	prx = current__.adapter.add(new UserSessionI(userId), userSessionId);
    	setSessionControl(userId, control); 
    	trace("New session created for userId=" + userId);
            return Glacier2.SessionPrxHelper.uncheckedCast(prx);
    }
    

    I recommend adding timeouts however to make sure to not wait indefinitely if something goes wrong between your server and Glacier2.

    Cheers,
    Benoit.