Jelajahi Sumber

HPCC-18603 Add ESP thread to clean session

Also fix a bug for reading session timeout setting

Signed-off-by: wangkx <kevin.wang@lexisnexis.com>
wangkx 7 tahun lalu
induk
melakukan
aa6c2a464e

+ 4 - 4
esp/bindings/http/platform/httpbinding.cpp

@@ -359,11 +359,11 @@ void EspHttpBinding::readAuthDomainCfg(IPropertyTree* procCfg)
         //Considering possible network delay, serverSessionTimeoutMinutes should be greater than clientSessionTimeoutMinutes.
         int serverSessionTimeoutMinutes = authDomainTree->getPropInt("@serverSessionTimeoutMinutes", 0);
         if ((serverSessionTimeoutMinutes < 0) || (clientSessionTimeoutMinutes < 0))
-            serverSessionTimeoutMinutes = ESP_SESSION_NEVER_TIMEOUT;
+            serverSessionTimeoutSeconds = ESP_SESSION_NEVER_TIMEOUT;
         else
-            serverSessionTimeoutMinutes = serverSessionTimeoutMinutes * 60;
-        if (serverSessionTimeoutMinutes < clientSessionTimeoutSeconds)
-            serverSessionTimeoutMinutes = 2 * clientSessionTimeoutSeconds;
+            serverSessionTimeoutSeconds = serverSessionTimeoutMinutes * 60;
+        if (serverSessionTimeoutSeconds < clientSessionTimeoutSeconds)
+            serverSessionTimeoutSeconds = 2 * clientSessionTimeoutSeconds;
 
         //The @unrestrictedResources contains URLs which may be used before a user is authenticated.
         //For example, an icon file on the login page.

+ 77 - 0
esp/platform/espcfg.cpp

@@ -111,11 +111,62 @@ StringBuffer &CVSBuildToEspVersion(char const * tag, StringBuffer & out)
     return out;
 }
 
+int CSessionCleaner::run()
+{
+    try
+    {
+        PROGLOG("CSessionCleaner Thread started.");
+
+        VStringBuffer xpath("%s*", PathSessionSession);
+        int checkSessionTimeoutMillSeconds = checkSessionTimeoutSeconds * 60;
+        while(!stopping)
+        {
+            Owned<IRemoteConnection> conn = querySDS().connect(espSessionSDSPath.get(), myProcessSession(), RTM_LOCK_WRITE, SESSION_SDS_LOCK_TIMEOUT);
+            if (!conn)
+                throw MakeStringException(-1, "Failed to connect to %s.", PathSessionRoot);
+
+            CDateTime now;
+            now.setNow();
+            time_t timeNow = now.getSimple();
+
+            Owned<IPropertyTreeIterator> iter1 = conn->queryRoot()->getElements(PathSessionApplication);
+            ForEach(*iter1)
+            {
+                ICopyArrayOf<IPropertyTree> toRemove;
+                Owned<IPropertyTreeIterator> iter2 = iter1->query().getElements(xpath.str());
+                ForEach(*iter2)
+                {
+                    IPropertyTree& item = iter2->query();
+                    if (timeNow >= item.getPropInt64(PropSessionTimeoutAt, 0))
+                        toRemove.append(item);
+                }
+                ForEachItemIn(i, toRemove)
+                {
+                    iter1->query().removeTree(&toRemove.item(i));
+                }
+            }
+            sem.wait(checkSessionTimeoutMillSeconds);
+        }
+    }
+    catch(IException *e)
+    {
+        StringBuffer msg;
+        ERRLOG("CSessionCleaner::run() Exception %d:%s", e->errorCode(), e->errorMessage(msg).str());
+        e->Release();
+    }
+    catch(...)
+    {
+        ERRLOG("Unknown CSessionCleaner::run() Exception");
+    }
+    return 0;
+}
+
 void CEspConfig::ensureSDSSessionDomains()
 {
     bool hasAuthDomainSettings = false;
     bool hasSessionAuth = false;
     bool hasDefaultSessionDomain = false;
+    int  serverSessionTimeoutSeconds = 120 * ESP_SESSION_TIMEOUT;
     Owned<IPropertyTree> proc_cfg = getProcessConfig(m_envpt, m_process.str());
     Owned<IPropertyTreeIterator> it = proc_cfg->getElements("AuthDomains/AuthDomain");
     ForEach(*it)
@@ -127,6 +178,24 @@ void CEspConfig::ensureSDSSessionDomains()
             continue;
 
         hasSessionAuth = true;
+
+        int clientSessionTimeoutSeconds;
+        int clientSessionTimeoutMinutes = authDomain.getPropInt("@clientSessionTimeoutMinutes", ESP_SESSION_TIMEOUT);
+        if (clientSessionTimeoutMinutes < 0)
+            clientSessionTimeoutSeconds = ESP_SESSION_NEVER_TIMEOUT;
+        else
+            clientSessionTimeoutSeconds = clientSessionTimeoutMinutes * 60;
+
+        //The serverSessionTimeoutMinutes is used to clean the sessions by ESP server after the sessions have been timed out on ESP clients.
+        //Considering possible network delay, serverSessionTimeoutMinutes should be greater than clientSessionTimeoutMinutes.
+        int serverSessionTimeoutMinutes = authDomain.getPropInt("@serverSessionTimeoutMinutes", 0);
+        if ((serverSessionTimeoutMinutes < 0) || (clientSessionTimeoutMinutes < 0))
+            serverSessionTimeoutSeconds = ESP_SESSION_NEVER_TIMEOUT;
+        else
+            serverSessionTimeoutSeconds = serverSessionTimeoutMinutes * 60;
+        if (serverSessionTimeoutSeconds < clientSessionTimeoutSeconds)
+            serverSessionTimeoutSeconds = 2 * clientSessionTimeoutSeconds;
+
         const char* authDomainName = authDomain.queryProp("@domainName");
         if (isEmptyString(authDomainName) || strieq(authDomainName, "default"))
         {
@@ -144,6 +213,14 @@ void CEspConfig::ensureSDSSessionDomains()
             throw MakeStringException(-1, "Failed to connect to %s.", PathSessionRoot);
 
         ensureESPSessionInTree(conn->queryRoot(), m_process.str());
+
+        if (serverSessionTimeoutSeconds != ESP_SESSION_NEVER_TIMEOUT)
+        {
+            VStringBuffer espSessionSDSPath("%s/%s[@name=\"%s\"]", PathSessionRoot, PathSessionProcess, m_process.str());
+            m_sessionCleaner.setown(new CSessionCleaner(espSessionSDSPath.str(), proc_cfg->getPropInt("@checkSessionTimeoutSeconds",
+                ESP_CHECK_SESSION_TIMEOUT)));
+            m_sessionCleaner->start();
+        }
     }
 }
 

+ 23 - 0
esp/platform/espcfg.ipp

@@ -101,12 +101,35 @@ struct esp_option
     { }
 };
 
+class CSessionCleaner : public Thread
+{
+    bool       stopping = false;;
+    Semaphore  sem;
+
+    StringAttr espSessionSDSPath;
+    int        checkSessionTimeoutSeconds; //the duration to clean timed out sesssions
+
+public:
+    CSessionCleaner(const char* _espSessionSDSPath, int _checkSessionTimeoutSeconds) : Thread("CSessionCleaner"),
+        espSessionSDSPath(_espSessionSDSPath), checkSessionTimeoutSeconds(_checkSessionTimeoutSeconds) { }
+
+    virtual ~CSessionCleaner()
+    {
+        stopping = true;
+        sem.signal();
+        join();
+    }
+
+    virtual int run();
+};
+
 class CEspConfig : public CInterface, implements IInterface 
 {
 private:
     Owned<IPropertyTree> m_envpt;
     Owned<IPropertyTree> m_cfg;
     Owned<IProperties> m_inputs;
+    Owned<CSessionCleaner> m_sessionCleaner;
 
     StringBuffer m_process;
     StringBuffer m_computer;