Disabling sessions for lift 2.0

112 views
Skip to first unread message

bmm

unread,
Jul 13, 2010, 4:04:00 PM7/13/10
to Lift
Hi all,


I'm new to lift and just started using lift 2.0. To get started, I
decided to create a very simple page: it only depends on the time of
the server and then shows you whether it's a holiday or not.

I started with the lift sbt project tarball and got that working
quickly. I then started to remove unneeded extras from src/main/scala/
bootstrap/liftweb/Boot.scala. I'm now left with only the following
source blow.

Dispite all this, using jetty I still get a jsessionID and (what is
actually pissing me off a bit) it will rewrite urls to insert the
jsessionid get parameter if I don't accept the cookies.

How can I stop the server from trying to initiate a session?

Greetings,
Bram

===================== Boot.scala
package bootstrap.liftweb

import _root_.net.liftweb.common._
import _root_.net.liftweb.util._
import _root_.net.liftweb.http._
import _root_.net.liftweb.http.provider._
import _root_.net.liftweb.sitemap._
import _root_.net.liftweb.sitemap.Loc._
import Helpers._
//import _root_.net.liftweb.mapper.{DB, ConnectionManager, Schemifier,
DefaultConnectionIdentifier, StandardDBVendor}
//import _root_.java.sql.{Connection, DriverManager}


/**
* A class that's instantiated early and run. It allows the
application
* to modify lift's environment
*/
class Boot {
def boot {
// where to search snippet
LiftRules.addToPackages("code")
//LiftRules.setSiteMap(SiteMap(Menu(Loc("Home", List("index"),
"Home"))))
LiftRules.enableContainerSessions = false
LiftRules.early.append(makeUtf8)
//S.addAround(DB.buildLoanWrapper)
}

/**
* Force the request to be UTF-8
*/
private def makeUtf8(req: HTTPRequest) {
req.setCharacterEncoding("UTF-8")
}
}
==================================

Timothy Perrett

unread,
Jul 13, 2010, 4:32:34 PM7/13/10
to lif...@googlegroups.com
Lift is highly stateful - you cant run it without a session of some kind in normal settings.

Certain things can be stateless, but if you use any of the form binding etc etc (basically, most of the stuff in lift that creates function closures) then you will be using state.

What is your use case for not needing a session at all? Depending upon what you want to do, it is possible. Generally speaking though, unless your like foursquare size or whatever, its a premature optimisation... Sessions != Evil all the time.

Cheers, Tim

> --
> You received this message because you are subscribed to the Google Groups "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
>
>

Okpala Ikenna N.

unread,
Jul 13, 2010, 4:37:50 PM7/13/10
to lif...@googlegroups.com
@tim i totally agree with on this one.. it is a great advantage that Lift is entirely stateful.

@bmm programatically i guess you can cut down the session all depending on the use case in context.

Okpala Ikenna N. Jr.

David Pollak

unread,
Jul 13, 2010, 5:18:09 PM7/13/10
to lif...@googlegroups.com
On Tue, Jul 13, 2010 at 1:04 PM, bmm <bne...@gmail.com> wrote:
Hi all,


I'm new to lift and just started using lift 2.0. To get started, I
decided to create a very simple page: it only depends on the time of
the server and then shows you whether it's a holiday or not.

I started with the lift sbt project tarball and got that working
quickly. I then started to remove unneeded extras from src/main/scala/
bootstrap/liftweb/Boot.scala. I'm now left with only the following
source blow.

Dispite all this, using jetty I still get a jsessionID and (what is
actually pissing me off a bit) it will rewrite urls to insert the
jsessionid get parameter if I don't accept the cookies.

How can I stop the server from trying to initiate a session?

You can't.

There are some REST things that can be defined as stateless, but anything that hits the HTML rendering pipeline requires a session.

If you're looking for something that doesn't initiate any form of session, you're not going to find it in Lift.  Sorry.
 
--
You received this message because you are subscribed to the Google Groups "Lift" group.
To post to this group, send email to lif...@googlegroups.com.
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.




--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics

Bram

unread,
Jul 15, 2010, 3:39:13 PM7/15/10
to lif...@googlegroups.com
Hi all,

Thank you all for the quick and direct replies.

The main reason I wanted to disable sessions is because I don't know how
the expired sessions are cleaned up and as a precaution the would be
better left out for my first ever lift deployment.

Knowing what I know now, I'm going to try to get my first lift site ever
online!

Greets,
Bram

Ross Mellgren

unread,
Jul 15, 2010, 3:42:59 PM7/15/10
to lif...@googlegroups.com
Sessions will be cleaned up by the container after some configurable idle time, usually 20-30 mins. Idle means no requests come in for that session. Note that by default Lift might send down javascript for GCing functions which will keep a session live while the browser is viewing that page.

I think David recently added some hooks for Harry that allow one to watch session creation/destruction in some detail, if you're interested.

-Ross

David Pollak

unread,
Jul 15, 2010, 3:54:17 PM7/15/10
to lif...@googlegroups.com
On Thu, Jul 15, 2010 at 12:39 PM, Bram <bne...@gmail.com> wrote:
Hi all,

Thank you all for the quick and direct replies.

The main reason I wanted to disable sessions is because I don't know how the expired sessions are cleaned up and as a precaution the would be better left out for my first ever lift deployment.

Bram,

I've got a fair amount of experience dealing with sessions in Lift.  I've distilled much of what I've learned into code in examples/example.  Here's code to periodically dump session info:

object SessionInfoDumper extends LiftActor with Loggable {
  private var lastTime = millis

  private def cyclePeriod = 1 minute

  import net.liftweb.example.lib.SessionChecker

  protected def messageHandler =
    {
      case SessionWatcherInfo(sessions) =>
        if ((millis - cyclePeriod) > lastTime) {
          lastTime = millis
          val rt = Runtime.getRuntime
          rt.gc

          RuntimeStats.lastUpdate = timeNow
          RuntimeStats.totalMem = rt.totalMemory
          RuntimeStats.freeMem = rt.freeMemory
          RuntimeStats.sessions = sessions.size

          val percent = (RuntimeStats.freeMem * 100L) / RuntimeStats.totalMem

          // get more aggressive about purging if we're
          // at less than 35% free memory
          if (percent < 35L) {
            SessionChecker.killWhen /= 2L
   if (SessionChecker.killWhen < 5000L) 
     SessionChecker.killWhen = 5000L
            SessionChecker.killCnt *= 2
          } else {
            SessionChecker.killWhen *= 2L
   if (SessionChecker.killWhen >
                SessionChecker.defaultKillWhen)
    SessionChecker.killWhen = SessionChecker.defaultKillWhen
            val newKillCnt = SessionChecker.killCnt / 2
   if (newKillCnt > 0) SessionChecker.killCnt = newKillCnt
          }

          val dateStr: String = timeNow.toString
          logger.info("[MEMDEBUG] At " + dateStr + " Number of open sessions: " + sessions.size)
          logger.info("[MEMDEBUG] Free Memory: " + pretty(RuntimeStats.freeMem))
          logger.info("[MEMDEBUG] Total Memory: " + pretty(RuntimeStats.totalMem))
          logger.info("[MEMDEBUG] Kill Interval: " + (SessionChecker.killWhen / 1000L))
          logger.info("[MEMDEBUG] Kill Count: " + (SessionChecker.killCnt))
        }
    }


  private def pretty(in: Long): String =
    if (in > 1000L) pretty(in / 1000L) + "," + (in % 1000L)
    else in.toString
}

and:

object SessionChecker extends Function2[Map[String, SessionInfo],
                                        SessionInfo => Unit, Unit] with Logger
{
  def defaultKillWhen = 180000L
  // how long do we wait to kill single browsers
  @volatile var killWhen = defaultKillWhen

  @volatile var killCnt = 1

  def apply(sessions: Map[String, SessionInfo],
            destroyer: SessionInfo => Unit): Unit = {
    val cutoff = millis - 180000L
    
    sessions.foreach {
      case (name, si @ SessionInfo(session, agent, _, cnt, lastAccess)) =>
        if (cnt <= killCnt && lastAccess < cutoff) {
          info("Purging "+agent)
          destroyer(si)
        }
    }
  }
}

And to enable the functionality in Boot.scala:

    SessionMaster.sessionCheckFuncs = SessionMaster.sessionCheckFuncs ::: List(SessionChecker)
    SessionMaster.sessionWatchers = SessionInfoDumper :: SessionMaster.sessionWatchers

The code sheds sessions based on some rules.  The rules are tuned every minute based on available memory and memory trends.  Basically, the code protects against creating lots of sessions during a search engine spider of the site.  Google will create 20 sessions per second and those sessions need to get shed quickly.  I use the code on http://demo.liftweb.net/  The last time the site went down was when I upgraded the site to run against Scala 2.8.0.RC7.

Thanks,

David

Peter Robinett

unread,
Jul 15, 2010, 8:43:55 PM7/15/10
to Lift
There's some great stuff in this thread so I copied over Ross and
David's posts to a new wiki page on sessions:
https://www.assembla.com/wiki/show/liftweb/Sessions

Please feel free to add to it.

Cheers,
Peter

On Jul 15, 9:54 pm, David Pollak <feeder.of.the.be...@gmail.com>
wrote:
> to get shed quickly.  I use the code onhttp://demo.liftweb.net/ The last
> >>> liftweb+u...@googlegroups.com<liftweb%2Bunsu...@googlegroups.com >
> >>> .
> >>> For more options, visit this group at
> >>>http://groups.google.com/group/liftweb?hl=en.
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "Lift" group.
> > To post to this group, send email to lif...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > liftweb+u...@googlegroups.com<liftweb%2Bunsu...@googlegroups.com >
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/liftweb?hl=en.
>
> --
> Lift, the simply functional web frameworkhttp://liftweb.net
> Beginning Scalahttp://www.apress.com/book/view/1430219890

Timothy Perrett

unread,
Jul 16, 2010, 3:36:44 AM7/16/10
to lif...@googlegroups.com
Excellent Peter, finally someone looking after the wiki!!

Sent from my iPhone

Peter Robinett

unread,
Jul 16, 2010, 8:21:57 AM7/16/10
to Lift
Happy to help. Hopefully this can compensate for my annoying tendency
to suggest things (e.g. Javascript DSL) and then drop the ball. ;)

Peter

Nuanda

unread,
Feb 26, 2011, 5:57:21 AM2/26/11
to lif...@googlegroups.com
Hmm, I accidentally sent this directly to DDP the first time. Anywho I've been looking at the Assembla page on Sessions:


And have a question: won't the SessionChecker code there always use 180secs as the idle threshold for when to run the session destroy function ?  ie., it seems to hardcode around the tuning done by the SessionInfoDumper.

i.e.,
val cutoff = millis - 180000L
should be?:
val cutoff = millis - killWhen

More broadly, doesn't the base SessionMaster.sessionCheckFuncs already include a function to destroy sessions based
on idle timeout? Is the need for the SessionChecker because Lift's default isn't aggressive enough on shedding sessions
for resource constrained sites with peaky loads?

Many thanks,

David Elliot

Reply all
Reply to author
Forward
0 new messages