Fix SessionStore concurrency in tests by debouncing fn
This commit is contained in:
parent
803bbfa0fe
commit
2256fbc1e8
@ -13,6 +13,5 @@ module.exports = {
|
|||||||
'jsx'
|
'jsx'
|
||||||
],
|
],
|
||||||
setupFiles: ['<rootDir>/jest.setup.js'],
|
setupFiles: ['<rootDir>/jest.setup.js'],
|
||||||
maxConcurrency: 1,
|
|
||||||
verbose: false
|
verbose: false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import {Store} from 'express-session'
|
import {Store} from 'express-session'
|
||||||
import {ISession} from './ISession'
|
import {ISession} from './ISession'
|
||||||
import {Repository, LessThan} from 'typeorm'
|
import {Repository, LessThan} from 'typeorm'
|
||||||
|
import {debounce} from '@rondo.dev/tasq'
|
||||||
|
|
||||||
type SessionData = Express.SessionData
|
type SessionData = Express.SessionData
|
||||||
type Callback = (err?: any, session?: SessionData) => void
|
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 {
|
export class SessionStore<S extends ISession> extends Store {
|
||||||
|
|
||||||
protected readonly getRepository: TRepositoryFactory<S>
|
protected readonly getRepository: TRepositoryFactory<S>
|
||||||
|
protected readonly cleanup: (...args: never[]) => void
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected readonly options: ISessionStoreOptions<S>,
|
protected readonly options: ISessionStoreOptions<S>,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
this.getRepository = options.getRepository
|
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>(
|
protected async promiseToCallback<T>(
|
||||||
@ -61,16 +75,17 @@ export class SessionStore<S extends ISession> extends Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set = (sid: string, session: SessionData, callback?: CallbackErr) => {
|
set = (sid: string, session: SessionData, callback?: CallbackErr) => {
|
||||||
const promise1 = this.options.cleanup
|
const promise = Promise.resolve()
|
||||||
? this.cleanup() : Promise.resolve()
|
.then(() => this.saveSession(
|
||||||
const promise2 = promise1.then(() => this.saveSession(
|
|
||||||
this.options.buildSession(session, {
|
this.options.buildSession(session, {
|
||||||
id: sid,
|
id: sid,
|
||||||
expiredAt: Date.now() + this.getTTL(session) * 1000,
|
expiredAt: Date.now() + this.getTTL(session) * 1000,
|
||||||
json: JSON.stringify(session),
|
json: JSON.stringify(session),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
this.promiseToCallback(promise2, callback)
|
this.promiseToCallback(promise, callback)
|
||||||
|
|
||||||
|
this.cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy = (sid: string, callback?: CallbackErr) => {
|
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
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
{"path": "../common"},
|
{"path": "../common"},
|
||||||
{"path": "../jsonrpc"},
|
{"path": "../jsonrpc"},
|
||||||
{"path": "../logger"},
|
{"path": "../logger"},
|
||||||
{"path": "../config"}
|
{"path": "../config"},
|
||||||
|
{"path": "../tasq"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,5 +10,6 @@
|
|||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"module": "lib/index.js"
|
"module": "lib/index.js",
|
||||||
|
"main": "lib/index.js"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
export function debounce<A, R>(fn: (...args: A[]) => R, delay: number) {
|
export function debounce<A, R>(fn: (...args: A[]) => R, delay: number) {
|
||||||
let timeout: NodeJS.Timeout | null = null
|
let timeout: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
return async function debounceImpl(...args: A[]) {
|
return function debounceImpl(...args: A[]): void {
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user