A Glacier2 router requires a client to create a session and forwards requests on behalf of the client until its session expires. A session expires when it is explicitly destroyed, or when it times out due to inactivity.
You can configure a router to use a custom session manager if your application needs to track the router's session activities. For example, your application may need to acquire resources and initialize the state of back-end services for each new session, and later reclaim those resources when the session expires.
As with the authentication facility, Glacier2 provides two session manager interfaces that an application can implement. The SessionManager
interface receives notifications about sessions that use password authentication, while the SSLSessionManager
interface is for sessions authenticated using SSL certificates.
On this page:
Glacier2 Session Manager Interfaces
The relevant Slice definitions are shown below:
module Glacier2 { exception CannotCreateSessionException { string reason; } interface Session { void destroy(); } interface SessionManager { Session* create(string userId, SessionControl* control) throws CannotCreateSessionException; } interface SSLSessionManager { Session* create(SSLInfo info, SessionControl* control) throws CannotCreateSessionException; } }
When a client creates a session by invoking createSession
on the Router
interface, the router validates the client's user name and password and then calls SessionManager::create
. Similarly, a call to createSessionFromSecureConnection
causes the router to invoke SSLSessionManager::create
. The SSLInfo
structure provides details about the client's SSL connection. The second argument to the create
operations is a proxy for a SessionControl
object, which a session can use to perform dynamic filtering.
The create
operations must return the proxy of a new Session
object, or raise CannotCreateSessionException
and provide an appropriate reason. The Session
proxy returned by create
is ultimately returned to the client as the result of createSession
or createSessionFromSecureConnection
.
Glacier2 invokes the destroy
operation on a Session
proxy when the session expires, giving a custom session manager the opportunity to reclaim resources that were acquired for the session during create
.
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.
To configure the router with a custom session manager, define the properties Glacier2.SessionManager
or Glacier2.SSLSessionManager
with the proxies of the session manager objects. If necessary, you can configure a router with proxies for both types of session managers. If a session manager proxy is not supplied, the call to createSession
or createSessionFromSecureConnection
always returns a null proxy.
The router attempts to contact the configured session manager at startup. If the object is unreachable, the router logs a warning message but continues its normal operation (you can suppress the warning using the --nowarn
option). The router does not contact the session manager again until it needs to invoke an operation on the object. For example, when a client asks the router to create a new session, the router makes another attempt to contact the session manager; if the session manager is still unavailable, the router logs a message and returns CannotCreateSessionException
to the client.
Example
A sample implementation of the SessionManager
interface is provided in the demo/Glacier2/callback
directory.
Glacier2 Session Timeouts
The value of the Glacier2.SessionTimeout
property specifies the number of seconds a session must be inactive before it expires. This property is not defined by default, which means sessions never expire due to inactivity. If a non-zero value is specified, it's very important that the application chooses a value that does not result in premature session expiration. For example, if it's normal for a client to create a session and then have long periods of inactivity, then a suitably long timeout must be chosen, or the connection must have periodic activity, or timeouts must be disabled altogether. Callbacks from a server to the client also keep a session alive, in which case Glacier2 automatically destroys the session if a failure occurs while forwarding a server callback to the client.
Once a session has expired (or been destroyed for some other reason), the client will no longer be able to send requests via the router and receives a ConnectionLostException
for each subsequent invocation. The client must explicitly create a new session in order to continue using the router.
In general, we recommend the use of an appropriate session timeout, otherwise resources created for each session will accumulate in the router.
The easiest way for a client to keep a session alive is to enable ACM heartbeats.
Connection Timeouts on Routed Proxies
The timeout for a client's connection to a Glacier2 router works the same as any other connection timeout: in addition to the timeout specified in a proxy's endpoints, several properties can also influence the timeout. For the sake of this discussion, let's ignore the properties and focus on the proxy endpoints.
Before we discuss timeouts, we need to briefly review some Glacier2 concepts. When a Glacier2 client configures a router proxy, normally by setting Ice.Default.Router
, it causes all proxies to become routed proxies. For an invocation on a routed proxy, the Ice run time in the client ignores that proxy's endpoints and instead forwards the invocation to the router for delivery.
There are two kinds of proxies here: the router proxy, and routed proxies. It's important to recognize this distinction in order to understand the following timeout semantics:
The endpoint timeout in the router proxy determines the connection timeout for the connection between the client and the router. Suppose we use the following settings:
Ice.Default.Router=Glacier2/router:tcp -h routerHost -p 4063 -t 10000 MyProxy=hello:tcp -h backEndHost -p 8888 -t 5000
This setting configures a ten second timeout for the client's connection to the router. Endpoint timeouts in routed proxies have no effect on this connection.
- The endpoint timeout in a routed proxy affects the router's connection to a back-end server. The Ice run time in the client internally registers routed proxies with the router because the router uses these proxies when it forwards invocations from the client to the desired back-end server. For the routed proxy
MyProxy
in the example above, the router would establish its own connection to port 8888 onbackEndHost
and configure a timeout of five seconds for that connection.
Again, it's critically important that the client's connection to the router remain open for as long as the client requires its session, as closing this connection effectively terminates the session. Since Ice interprets the occurrence of a connection timeout as a hard error and closes the offending connection, select your timeout for the router proxy with care.
As of Ice 3.6, a Glacier2 client can safely use invocation timeouts and active connection management.
For invocations made by Glacier2 to a back-end server, whatever timeout value is set on the first proxy that is used to make an invocation applies to all proxies for the same object. This is necessary because Glacier2 adds the proxy to its routing table during the first invocation and, thereafter, reuses that cached proxy for all invocations to the same object identity. Here is an example to illustrate this:
// 10-second timeout for the connection to the router. auto router = communicator->stringToProxy("Glacier2/router:tcp -h routerHost -p 4063 -t 10000"); communicator->setDefaultRouter(Ice::uncheckedCast<RouterPrx>(router)); // Ping back-end server with 20-second timeout communicator->stringToProxy("id:tcp -h backEndHost -p 8888 -t 20000")->ice_ping(); // Ping back-end server with 30-second timeout communicator->stringToProxy("id:tcp -h backEndHost -p 8888 -t 30000")->ice_ping();
// 10-second timeout for the connection to the router. ObjectPrx router = communicator->stringToProxy("Glacier2/router:tcp -h routerHost -p 4063 -t 10000"); communicator->setDefaultRouter(RouterPrx::uncheckedCast(router)); // Ping back-end server with 20-second timeout communicator->stringToProxy("id:tcp -h backEndHost -p 8888 -t 20000")->ice_ping(); // Ping back-end server with 30-second timeout communicator->stringToProxy("id:tcp -h backEndHost -p 8888 -t 30000")->ice_ping();
The first call to ice_ping
, when forwarded by Glacier2 to the server, establishes a connection with a 20-second timeout. The second call to ice_ping
reuses the existing connection with a 20-second timeout, even though the proxy specifies a 30-second timeout.
Connection Caching for Session Managers
You can distribute the load among multiple session manager objects by configuring the router with a session manager proxy that contains multiple endpoints. Glacier2 disables connection caching on this proxy so that each invocation on a session manager attempts to use a different endpoint.
This behavior achieves a basic form of load balancing without depending on the replication features provided by IceGrid. Be aware that including an invalid endpoint in your session manager proxy, such as the endpoint of a session manager server that is not currently running, can cause router clients to experience delays during session creation.
If your session managers are in an IceGrid replica group, refer to IceGrid and Glacier2 Integration for more information on the router's caching behavior.