Do all session pruning in a single goroutine

This commit is contained in:
Ken-Håvard Lieng 2018-06-01 05:40:12 +02:00
parent e8f5809940
commit c49bbc72d4
3 changed files with 38 additions and 20 deletions

View File

@ -35,6 +35,8 @@ func (d *Dispatch) handleAuth(w http.ResponseWriter, r *http.Request, createUser
d.states.deleteSession(key) d.states.deleteSession(key)
session.SetCookie(w, r) session.SetCookie(w, r)
} }
} else {
d.states.deleteSession(key)
} }
} }
@ -76,7 +78,6 @@ func (d *Dispatch) newUser(w http.ResponseWriter, r *http.Request) (*State, erro
return nil, err return nil, err
} }
d.states.setSession(session) d.states.setSession(session)
go d.deleteSessionWhenExpired(session)
state := NewState(user, d) state := NewState(user, d)
d.states.set(state) d.states.set(state)
@ -86,12 +87,3 @@ func (d *Dispatch) newUser(w http.ResponseWriter, r *http.Request) (*State, erro
return state, nil return state, nil
} }
func (d *Dispatch) deleteSessionWhenExpired(session *session.Session) {
deleteSessionWhenExpired(session, d.states)
}
func deleteSessionWhenExpired(session *session.Session, stateStore *stateStore) {
session.WaitUntilExpiration()
stateStore.deleteSession(session.Key())
}

View File

@ -45,6 +45,7 @@ func (d *Dispatch) Run() {
session.CookieName = "dispatch" session.CookieName = "dispatch"
d.states = newStateStore(d.SessionStore) d.states = newStateStore(d.SessionStore)
go d.states.run()
d.loadUsers() d.loadUsers()
d.initFileServer() d.initFileServer()
@ -57,7 +58,7 @@ func (d *Dispatch) loadUsers() {
log.Fatal(err) log.Fatal(err)
} }
log.Printf("Loading %d user(s)", len(users)) log.Printf("[Init] %d users", len(users))
for _, user := range users { for _, user := range users {
go d.loadUser(user) go d.loadUser(user)

View File

@ -244,11 +244,12 @@ func newStateStore(sessionStore storage.SessionStore) *stateStore {
log.Fatal(err) log.Fatal(err)
} }
log.Printf("[Init] %d sessions", len(sessions))
for _, session := range sessions { for _, session := range sessions {
if !session.Expired() { if !session.Expired() {
session.Init() session.Init()
store.sessions[session.Key()] = session store.sessions[session.Key()] = session
go deleteSessionWhenExpired(session, store)
} else { } else {
go sessionStore.DeleteSession(session.Key()) go sessionStore.DeleteSession(session.Key())
} }
@ -257,6 +258,22 @@ func newStateStore(sessionStore storage.SessionStore) *stateStore {
return store return store
} }
func (s *stateStore) run() {
pruneSessions := time.Tick(time.Minute * 5)
for {
select {
case <-pruneSessions:
s.lock.Lock()
for key, session := range s.sessions {
if session.Expired() {
s.internalDeleteSession(key)
}
}
s.lock.Unlock()
}
}
}
func (s *stateStore) get(id uint64) *State { func (s *stateStore) get(id uint64) *State {
s.lock.Lock() s.lock.Lock()
state := s.states[id] state := s.states[id]
@ -298,26 +315,34 @@ func (s *stateStore) setSession(session *session.Session) {
func (s *stateStore) deleteSession(key string) { func (s *stateStore) deleteSession(key string) {
s.lock.Lock() s.lock.Lock()
s.internalDeleteSession(key)
s.lock.Unlock()
}
func (s *stateStore) internalDeleteSession(key string) {
id := s.sessions[key].UserID id := s.sessions[key].UserID
delete(s.sessions, key) delete(s.sessions, key)
n := 0 n := 0
for _, session := range s.sessions { for _, session := range s.sessions {
if session.UserID == id { if session.UserID == id {
n++ n++
} }
} }
state := s.states[id] state := s.states[id]
if n == 0 { if n == 0 {
delete(s.states, id) delete(s.states, id)
} }
s.lock.Unlock()
if n == 0 { go func() {
// This anonymous user is not reachable anymore since all sessions have if n == 0 {
// expired, so we clean it up // This anonymous user is not reachable anymore since all sessions have
state.kill() // expired, so we clean it up
state.user.Remove() state.kill()
} state.user.Remove()
}
go s.sessionStore.DeleteSession(key) s.sessionStore.DeleteSession(key)
}()
} }