Fix SessionStore concurrency in tests by debouncing fn

This commit is contained in:
Jerko Steiner 2019-08-26 20:13:35 +07:00
parent 803bbfa0fe
commit 2256fbc1e8
5 changed files with 24 additions and 16 deletions

View File

@ -13,6 +13,5 @@ module.exports = {
'jsx'
],
setupFiles: ['<rootDir>/jest.setup.js'],
maxConcurrency: 1,
verbose: false
}

View File

@ -1,6 +1,7 @@
import {Store} from 'express-session'
import {ISession} from './ISession'
import {Repository, LessThan} from 'typeorm'
import {debounce} from '@rondo.dev/tasq'
type SessionData = Express.SessionData
type Callback = (err?: any, session?: SessionData) => void
@ -23,12 +24,25 @@ export type TRepositoryFactory<T> = () => Repository<T>
export class SessionStore<S extends ISession> extends Store {
protected readonly getRepository: TRepositoryFactory<S>
protected readonly cleanup: (...args: never[]) => void
constructor(
protected readonly options: ISessionStoreOptions<S>,
) {
super()
this.getRepository = options.getRepository
this.cleanup = debounce(async () => {
try {
const now = Date.now()
// FIXME causes deadlocks in tests
await this.getRepository().delete({
expiredAt: LessThan(now),
} as any)
} catch (err) {
console.log('error cleaning sessions', err)
}
}, 1000)
}
protected async promiseToCallback<T>(
@ -61,16 +75,17 @@ export class SessionStore<S extends ISession> extends Store {
}
set = (sid: string, session: SessionData, callback?: CallbackErr) => {
const promise1 = this.options.cleanup
? this.cleanup() : Promise.resolve()
const promise2 = promise1.then(() => this.saveSession(
const promise = Promise.resolve()
.then(() => this.saveSession(
this.options.buildSession(session, {
id: sid,
expiredAt: Date.now() + this.getTTL(session) * 1000,
json: JSON.stringify(session),
}),
))
this.promiseToCallback(promise2, callback)
this.promiseToCallback(promise, callback)
this.cleanup()
}
destroy = (sid: string, callback?: CallbackErr) => {
@ -99,12 +114,4 @@ export class SessionStore<S extends ISession> extends Store {
return typeof maxAge === 'number' ? maxAge : this.options.ttl
}
protected async cleanup() {
const now = Date.now()
// FIXME causes deadlocks in tests
await this.getRepository().delete({
expiredAt: LessThan(now),
} as any)
}
}

View File

@ -8,6 +8,7 @@
{"path": "../common"},
{"path": "../jsonrpc"},
{"path": "../logger"},
{"path": "../config"}
{"path": "../config"},
{"path": "../tasq"}
]
}

View File

@ -10,5 +10,6 @@
"dependencies": {},
"types": "lib/index.d.ts",
"devDependencies": {},
"module": "lib/index.js"
"module": "lib/index.js",
"main": "lib/index.js"
}

View File

@ -1,7 +1,7 @@
export function debounce<A, R>(fn: (...args: A[]) => R, delay: number) {
let timeout: NodeJS.Timeout | null = null
return async function debounceImpl(...args: A[]) {
return function debounceImpl(...args: A[]): void {
if (timeout) {
clearTimeout(timeout)
}