Fix connection reservation logic (#9153)
Some checks are pending
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / uitest-workspaces (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions

This commit is contained in:
Denis Bykhov 2025-06-03 06:52:04 +05:00 committed by GitHub
parent 51cc82b175
commit 1705a46bb4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 15 additions and 28 deletions

View File

@ -53,7 +53,7 @@ export interface SessionData {
workspace: WorkspaceIds workspace: WorkspaceIds
socialStringsToUsers: Map<PersonId, AccountUuid> socialStringsToUsers: Map<PersonId, AccountUuid>
asyncRequests?: (() => Promise<void>)[] asyncRequests?: ((ctx: MeasureContext) => Promise<void>)[]
} }
/** /**

View File

@ -179,7 +179,7 @@ export class TriggersMiddleware extends BaseMiddleware implements Middleware {
} else { } else {
ctx.contextData.asyncRequests = [ ctx.contextData.asyncRequests = [
...(ctx.contextData.asyncRequests ?? []), ...(ctx.contextData.asyncRequests ?? []),
async () => { async (ctx) => {
// In case of async context, we execute both async and sync triggers as sync // In case of async context, we execute both async and sync triggers as sync
await this.processAsyncTriggers(ctx, triggerControl, findAll, txes, triggers) await this.processAsyncTriggers(ctx, triggerControl, findAll, txes, triggers)
} }

View File

@ -139,12 +139,12 @@ class ConnectionInfo {
readonly managed: boolean readonly managed: boolean
) {} ) {}
async withReserve (reserveOrPool: boolean, action: (reservedClient: DBClient) => Promise<any>): Promise<any> { async withReserve (action: (reservedClient: DBClient) => Promise<any>, forced: boolean = false): Promise<any> {
let reserved: DBClient | undefined let reserved: DBClient | undefined
// Check if we have at least one available connection and reserve one more if required. // Check if we have at least one available connection and reserve one more if required.
if (this.available.length === 0) { if (this.available.length === 0) {
if (reserveOrPool) { if (this.managed || forced) {
reserved = await this.client.reserve() reserved = await this.client.reserve()
} }
} else { } else {
@ -164,24 +164,12 @@ class ConnectionInfo {
} catch (err: any) { } catch (err: any) {
console.error('failed to release', err) console.error('failed to release', err)
} }
} else { } else if (reserved !== undefined) {
// after use we put into available if (this.available.length > 0) {
if (reserved !== undefined) { reserved?.release()
} else {
this.available.push(reserved) this.available.push(reserved)
} }
if (this.available.length > 1) {
// We need to release any >= 1
const toRelease = this.available.splice(1, this.available.length - 1)
for (const r of toRelease) {
try {
r.release()
} catch (err: any) {
console.error('failed to relase', err)
}
}
}
} }
} }
} }
@ -212,7 +200,7 @@ class ConnectionMgr {
try { try {
while (true) { while (true) {
const retry: boolean | Error = await connection.withReserve(true, async (client) => { const retry: boolean | Error = await connection.withReserve(async (client) => {
tries++ tries++
try { try {
await client.execute('BEGIN;') await client.execute('BEGIN;')
@ -231,7 +219,7 @@ class ConnectionMgr {
return false return false
} }
} }
}) }, true)
if (retry === true) { if (retry === true) {
break break
} }
@ -261,7 +249,7 @@ class ConnectionMgr {
try { try {
while (true) { while (true) {
const retry: false | { result: any } | Error = await connection.withReserve(false, async (client) => { const retry: false | { result: any } | Error = await connection.withReserve(async (client) => {
tries++ tries++
try { try {
return { result: await fn(client) } return { result: await fn(client) }

View File

@ -318,9 +318,8 @@ export function getDBClient (
database, database,
max: 10, max: 10,
min: 2, min: 2,
connect_timeout: 10, connect_timeout: 30,
idle_timeout: 30, idle_timeout: 0,
max_lifetime: 300,
transform: { transform: {
undefined: null undefined: null
}, },

View File

@ -251,8 +251,8 @@ export class ClientSession implements Session {
onEnd = useReserveContext ? ctx.pipeline.context.adapterManager?.reserveContext?.(cid) : undefined onEnd = useReserveContext ? ctx.pipeline.context.adapterManager?.reserveContext?.(cid) : undefined
const handleAyncs = async (): Promise<void> => { const handleAyncs = async (): Promise<void> => {
try { try {
for (const r of (ctx.ctx.contextData as SessionData).asyncRequests ?? []) { for (const r of asyncs) {
await r() await r(ctx.ctx)
} }
} finally { } finally {
onEnd?.() onEnd?.()