42 votes

I think I fixed what was causing some people to be unable to stay logged in

Tags: changelog

One of the main complaints so far has been that some people have been having trouble staying logged in (until randomly it just seems to work for no apparent reason). Examples: Here and here and here and here and probably even more.

I think I've figured out (and fixed) the issue now, so if you get unexpectedly logged out again after your next login, please let me know. I think the existing sessions may still have the issue, so I'm not totally sure if it will be fixed until after a new login (and even then, I'm still not totally sure).

18 comments

  1. [12]
    Emerald_Knight
    Link
    Would it be possible to get a brief postmortem for the suspected cause? I love digging into the root causes of problems :)

    Would it be possible to get a brief postmortem for the suspected cause? I love digging into the root causes of problems :)

    9 votes
    1. [11]
      Deimos
      Link Parent
      I can try, I think it might be fairly confusing though. I'm sure you know this part, but for the benefit of other readers: sites generally maintain your login with a couple of pieces. Your browser...

      I can try, I think it might be fairly confusing though.

      I'm sure you know this part, but for the benefit of other readers: sites generally maintain your login with a couple of pieces. Your browser stores a cookie that contains a (very long, hopefully impossible to guess) session identifier of some sort, which is associated with some server-side data related to the session. Whenever your browser loads a page on the site, it also sends along the session identifier cookie, and the server uses that to look up the data and figure out which account you're logged into.

      The library I'm using to manage sessions is pyramid_session_redis, which stores the server-side session data inside Redis. Redis supports storing data with a TTL (Time To Live), and it will automatically delete that data after that amount of time expires. So the way the session library is supposed to keep the sessions alive is by regularly refreshing the TTL on the session data.

      If you don't check the "keep me logged in" box on Tildes, your session is set to expire after 1 day. Every time you access a page on Tildes, the session library uses your cookie to look up your session data from Redis, and then also updates the TTL to 1 day again. If you don't access the site for over 24 hours, the TTL will expire and Redis will delete the data. Then, next time you come to the site, the cookie won't correspond to a valid session any more (it was deleted), and the site will start a new session for you, which effectively logs you out.

      The problem, if I'm understanding this right, is that the developer of the session library was trying to reduce the number of commands the library was sending to Redis. Because you need to refresh the TTL constantly to keep the session data around, it means that every time a user loads a page, you have to send two separate Redis commands - GET (get the data) and EXPIRE (refresh the TTL). To try to reduce this, he implemented something that will only send the EXPIRE command when the session is getting close to expiry. I think the idea was something like, "if your sessions last an hour, it's not really worth refreshing it when they still have 55 minutes left", so by default, it will only refresh a session when there are less than 10 minutes left in it.

      But there's a problem if the person doesn't visit the site inside that last 10 minutes: the session's TTL hasn't been getting refreshed, and if they miss the "refresh window" it just times out and gets deleted. So for the one-hour session case, if a user uses the site for 45 minutes, then leaves for 30 and comes back, their session will have expired, even though it was supposed to require an hour of idle time before that could happen.

      For Tildes specifically, it looks like this was made worse by me doing things in a bit of a strange way—when you visit Tildes logged-out, you get assigned a one-hour session initially. Since the site is invite-only, I didn't want to keep a bunch of useless session data around for people that were just checking the site and then leaving when they realized they couldn't register. So I start with that one-hour session and when you log in, update it to either a one-day or a one-year one, depending on whether you check "keep me logged in".

      Because of that combined with the 10 minute "refresh window", the session wouldn't get extended to the longer length unless the person made at least one request to the site during the window. This is why it seemed to be so inconsistent for people—it was entirely dependent on whether they just happened to do something on the site 50-59 minutes after their session started. If they did, the session would "extend" properly to a year, but if they didn't, it would time out.

      Did that... make any sense at all?

      18 votes
      1. [5]
        Emerald_Knight
        Link Parent
        Absolutely. Don't worry, I do web programming for a living. I'm basically unofficial full-stack. So you explained things way more simply than was actually necessary, but that's perfectly fine...

        Did that... make any sense at all?

        Absolutely. Don't worry, I do web programming for a living. I'm basically unofficial full-stack. So you explained things way more simply than was actually necessary, but that's perfectly fine because it will be very digestible to others reading.

        It's interesting that the pyramid_session_redis dev chose to go that route. I would call that little "optimization" a hack, and generally hacks should be either avoided or really, really well-documented if they can't be.

        Thanks for the rundown!

        6 votes
        1. [4]
          Deimos
          (edited )
          Link Parent
          I agree, I feel like I might be misunderstanding how it works because it really doesn't make sense to me if that "refresh window" concept is right. Having the default behavior be that the session...

          I agree, I feel like I might be misunderstanding how it works because it really doesn't make sense to me if that "refresh window" concept is right. Having the default behavior be that the session won't refresh if it's not accessed in the last 10 minutes before it expires seems like it will only be reasonable if your use case is very short, active sessions.

          2 votes
          1. [3]
            Emerald_Knight
            Link Parent
            It's hard to say without having dug around in their source code or seeing the corresponding calls in the Tildes source code. I wouldn't be surprised at all, though. Programmers try to do "clever"...

            It's hard to say without having dug around in their source code or seeing the corresponding calls in the Tildes source code. I wouldn't be surprised at all, though. Programmers try to do "clever" things all the time and end up shooting themselves in the foot because they're relying on faulty assumptions or just piling on more technical debt with wild abandon.

            I'll be sure to take a deeper look into this at some point and see if I can verify any of this. If I find anything, I'll be sure to let you know :)

            3 votes
            1. [2]
              Deimos
              Link Parent
              No need—I submitted an issue on the library about it, and the dev confirmed that's how it works. So now I'll try to convince him that this is way too unexpected to be the default behavior.

              No need—I submitted an issue on the library about it, and the dev confirmed that's how it works. So now I'll try to convince him that this is way too unexpected to be the default behavior.

              4 votes
              1. Emerald_Knight
                Link Parent
                Duly noted. Yeah, that sort of optimization should really not be the default and should be a well-documented configuration option that can be set if desired, with notes about potential caveats.

                Duly noted. Yeah, that sort of optimization should really not be the default and should be a well-documented configuration option that can be set if desired, with notes about potential caveats.

                2 votes
      2. [2]
        zowesiouff
        (edited )
        Link Parent
        From reading the GH issue ( for technical readers out there: it's an interesting one, and not necessarily premature optimisation material ), I suppose you now have disabled that 10 minute "refresh...

        Because of that combined with the 10 minute "refresh window", the session wouldn't get extended to the longer length unless the person made at least one request to the site during the window. This is why it seemed to be so inconsistent for people—it was entirely dependent on whether they just happened to do something on the site 50-59 minutes after their session started. If they did, the session would "extend" properly to a year, but if they didn't, it would time out.

        From reading the GH issue ( for technical readers out there: it's an interesting one, and not necessarily premature optimisation material ), I suppose you now have disabled that 10 minute "refresh window"?

        Would it make sense to fix it by having the session timeout extensions ( going from 1 hour to 1 day or 1 hour to 1 year ) execute immediately, but keep the refresh windows for all other actions? and potentially increase the refresh window to 50% of the session timeout? ( not sure if you can have it dependent on the session timeout, but worst case you could probably set it at 50% of 1 day? )

        If you bump it to 2 days with a 50% refresh window, you effectively require users to be active every other day, but you're making sure that only the first action in that day is calling EXPIRE?

        ( I haven't tested any of this, so I might be missing a crucial piece of info that would make all of this moot :D And I also think this maybe should be completely handle by the library and be completely transparent to the library end user )

        4 votes
        1. Deimos
          Link Parent
          Yeah, I had disabled it (but the dev has disabled it by default now too). I think there are lots of possibilities if it does need to be optimized (though unfortunately most of them probably make...

          Yeah, I had disabled it (but the dev has disabled it by default now too).

          I think there are lots of possibilities if it does need to be optimized (though unfortunately most of them probably make the session behavior less reliable), but I'm not going to worry about it for now, unless I start seeing it look like redis is struggling to keep up.

          3 votes
      3. [3]
        Elusive
        Link Parent
        Interestingly, I don't seem to have had this issue at all since initially logging in. It seems very unlikely that I hit that 10 minute window every single time so far.

        Interestingly, I don't seem to have had this issue at all since initially logging in. It seems very unlikely that I hit that 10 minute window every single time so far.

        1. [2]
          zowesiouff
          Link Parent
          If I understood it properly, if you hit it the first time after signing up / logging in ( so you stayed active for 50 minutes after logging in with "keep me logged in" ) and managed to get your...

          If I understood it properly, if you hit it the first time after signing up / logging in ( so you stayed active for 50 minutes after logging in with "keep me logged in" ) and managed to get your session timeout set to 1 year that way, you shouldn't have any issue until 1 year from now where you would have a tiny 10 mins window to actually refresh your session :) Some kind of birthday gift from ~ ;)

          4 votes
          1. Elusive
            Link Parent
            That makes sense. I somehow overlooked the year-long expiry part. Speaking of birthday gifts, is there going to be a "cake day" equivalent of some sort? :)

            That makes sense. I somehow overlooked the year-long expiry part.

            Speaking of birthday gifts, is there going to be a "cake day" equivalent of some sort? :)

            1 vote
  2. Ten
    Link
    I love you @deimos Seems to be working well on my end.

    I love you @deimos

    Seems to be working well on my end.

    4 votes
  3. bigbert
    Link
    As a very lazy person I thank you!

    As a very lazy person I thank you!

    2 votes
  4. zero5549
    Link
    Awesome! Thank you.

    Awesome! Thank you.

    1 vote