Hi,

On some applications we have:
- quite low number of users most of the time
- high number of users twice a year

These applications store quite a lot of information in session.
To cope with the surge of users, we would need to:
- either increase mx (Java max memory)
- or use short session timeout (lifetime)
- or use horizontal scaling (k8s... but we currently have no such solutions)

The best solution for us would be a "maxActiveSessions" setting which would set 
a high bound to the number of sessions,
but compared to current implementation, it would allow new sessions and expire 
old sessions.

We mostly achieved this with a cron (1) calling a script (2): it uses 
tomcat-manager to force a shorter lifetime when there is a lot of sessions.

Since it would be nicer to have this behavior directly in tomcat, I did it 
using a small class extending StandardManager (2).
I wonder if this could be useful to other users?...

cu.


(1) */10 * * * * ~/tomcat/expire-if-too-many-sessions student-info 4000 8
(2) script "expire-if-too-many-sessions":
--------------
webapp=$1
max_sessions=$2
idle=$3

nb_sessions=`curl -s --user "$user" "$url/manager/text/list" | grep "$webapp" | 
awk -F: '{print $3}'`

if [ $nb_sessions -gt $max_sessions ]; then
    echo "too many sessions ($nb_sessions > $max_sessions). telling tomcat to expire 
$webapp sessions inactive more than $idle"
    out=`curl -s --user "$user" 
"$url/manager/text/expire?path=/$webapp&idle=$idle"`
    if echo $out | grep -q '^OK'; then
        :
    else
        echo "error expiring: $out"
    fi
fi
-------------


(3)
-------------
    protected int maxActiveSessionsGoal = -1;

    /**
     * If you have too many sessions, you may memory overflow.
     * This setting will expire old sessions to keep sessions memory usage low.
     * -1 is no limit
     */
    public void setMaxActiveSessionsGoal(int max) {
        maxActiveSessionsGoal = max;
    }


    public void processExpires() {
        super.processExpires();
        if (maxActiveSessionsGoal >= 0) {
            var nb = getActiveSessions();
            if (nb > maxActiveSessionsGoal) {
                expireNbOldSessions(nb - maxActiveSessionsGoal);
            }
        }
    }

    private void expireNbOldSessions(int nbToRemove) {
        var time = sessions.values().stream()
            .mapToLong(Session::getLastAccessedTimeInternal).sorted()
            // we want the nbToRemove-th element in the array
            .skip(nbToRemove).findFirst()
            .orElse(0);
        if (time == 0) {
            log.error("internal error expireNbOldSessions");
            return;
        }
        log.info("To achieve maxActiveSessionsGoal (" + maxActiveSessionsGoal + ") for " + 
getContext().getBaseName() + ", we will expire sessions older than " + new Date(time) + " (" + nbToRemove + 
" sessions)");
        for (Session session : findSessions()) {
            if (session.getLastAccessedTimeInternal() < time) {
                session.expire();
            }
        }
    }
-------------

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to