make server crash more visible in logs, try fixing bug with query builder

This commit is contained in:
einhornimmond 2025-10-14 10:53:07 +02:00
parent 412557b76d
commit 0ce9eaab3d
5 changed files with 122 additions and 15 deletions

View File

@ -1,8 +1,9 @@
import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity } from '..'
import { AppDatabase } from '../AppDatabase'
import { getHomeCommunity, getHomeCommunityWithFederatedCommunityOrFail, getReachableCommunities } from './communities'
import { getCommunityByPublicKeyOrFail, getHomeCommunity, getHomeCommunityWithFederatedCommunityOrFail, getReachableCommunities } from './communities'
import { describe, expect, it, beforeEach, beforeAll, afterAll } from 'vitest'
import { createCommunity, createVerifiedFederatedCommunity } from '../seeds/community'
import { Ed25519PublicKey } from 'shared'
const db = AppDatabase.getInstance()
@ -56,6 +57,18 @@ describe('community.queries', () => {
await createCommunity(false)
expect(() => getHomeCommunityWithFederatedCommunityOrFail('1_0')).rejects.toThrow()
})
it('load community by public key returned from getHomeCommunityWithFederatedCommunityOrFail', async () => {
const homeCom = await createCommunity(false)
await createVerifiedFederatedCommunity('1_0', 100, homeCom)
const community = await getHomeCommunityWithFederatedCommunityOrFail('1_0')
expect(community).toBeDefined()
expect(community?.federatedCommunities).toHaveLength(1)
const ed25519PublicKey = new Ed25519PublicKey(community.federatedCommunities![0].publicKey)
const communityByPublicKey = await getCommunityByPublicKeyOrFail(ed25519PublicKey)
expect(communityByPublicKey).toBeDefined()
expect(communityByPublicKey?.communityUuid).toBe(homeCom.communityUuid)
})
})
describe('getReachableCommunities', () => {
it('home community counts also to reachable communities', async () => {

View File

@ -0,0 +1,79 @@
import { AppDatabase } from '../AppDatabase'
import {
CommunityHandshakeState as DbCommunityHandshakeState,
Community as DbCommunity,
FederatedCommunity as DbFederatedCommunity,
getHomeCommunityWithFederatedCommunityOrFail,
getCommunityByPublicKeyOrFail,
findPendingCommunityHandshake,
CommunityHandshakeStateType
} from '..'
import { describe, expect, it, beforeEach, beforeAll, afterAll } from 'vitest'
import { createCommunity, createVerifiedFederatedCommunity } from '../seeds/community'
import { Ed25519PublicKey } from 'shared'
const db = AppDatabase.getInstance()
beforeAll(async () => {
await db.init()
})
afterAll(async () => {
await db.destroy()
})
describe('communityHandshakes', () => {
// clean db for every test case
beforeEach(async () => {
await DbCommunity.clear()
await DbFederatedCommunity.clear()
await DbCommunityHandshakeState.clear()
})
it('should find pending community handshake by public key', async () => {
const com1 = await createCommunity(false)
await createVerifiedFederatedCommunity('1_0', 100, com1)
const state = new DbCommunityHandshakeState()
state.publicKey = com1.publicKey
state.apiVersion = '1_0'
state.status = CommunityHandshakeStateType.OPEN_CONNECTION_CALLBACK
state.handshakeId = 1
await state.save()
const communityHandshakeState = await findPendingCommunityHandshake(new Ed25519PublicKey(com1.publicKey), '1_0')
expect(communityHandshakeState).toBeDefined()
expect(communityHandshakeState).toMatchObject({
publicKey: com1.publicKey,
apiVersion: '1_0',
status: CommunityHandshakeStateType.OPEN_CONNECTION_CALLBACK,
handshakeId: 1
})
})
it('try to use returned public key for loading community', async () => {
// test this explicit case, because in federation.authentication it lead to server crash
const com1 = await createCommunity(false)
await createVerifiedFederatedCommunity('1_0', 100, com1)
const state = new DbCommunityHandshakeState()
state.publicKey = com1.publicKey
state.apiVersion = '1_0'
state.status = CommunityHandshakeStateType.OPEN_CONNECTION_CALLBACK
state.handshakeId = 1
await state.save()
const communityHandshakeState = await findPendingCommunityHandshake(new Ed25519PublicKey(com1.publicKey), '1_0')
expect(communityHandshakeState).toBeDefined()
expect(communityHandshakeState?.federatedCommunity?.community).toBeDefined()
const ed25519PublicKey = new Ed25519PublicKey(communityHandshakeState?.federatedCommunity?.community?.publicKey)
const community = await DbCommunity.findOneBy({ publicKey: ed25519PublicKey.asBuffer() })
expect(community).toBeDefined()
expect(community).toMatchObject({
communityUuid: com1.communityUuid,
name: com1.name,
description: com1.description,
url: com1.url,
creationDate: com1.creationDate,
authenticatedAt: com1.authenticatedAt,
foreign: com1.foreign,
publicKey: com1.publicKey,
privateKey: com1.privateKey
})
})
})

View File

@ -10,7 +10,7 @@ import {
FederatedCommunityLoggingView,
getHomeCommunity,
findPendingCommunityHandshakeOrFailByOneTimeCode,
getCommunityByPublicKeyOrFail,
Community as DbCommunity,
} from 'database'
import { getLogger } from 'log4js'
import {
@ -170,16 +170,20 @@ export class AuthenticationResolver {
`invalid uuid: ${authArgs.uuid} for community with publicKey ${authComPublicKey.asHex()}`
)
}
methodLogger.debug('before loading auth community again from db')
const authComFresh = await getCommunityByPublicKeyOrFail(argsPublicKey)
authComFresh.communityUuid = communityUuid.data
authComFresh.authenticatedAt = new Date()
methodLogger.debug('after loading auth community again from db')
methodLogger.debug('try to save: ', authComFresh)
await authComFresh.save().catch((err) => {
methodLogger.fatal('failed to save authCom:', err)
})
methodLogger.debug('store authCom.uuid successfully:', new CommunityLoggingView(authCom))
methodLogger.debug('before updating auth community again from db')
// need to use query builder, loading from db, changing and save lead to server crash with this error:
// TypeError [ERR_INVALID_ARG_TYPE]: The "otherBuffer" argument must be of type Buffer or Uint8Array. Received an instance of Object
// seems to be a typeorm problem with Buffer, even if I give a freshly created Buffer for public_key
await DbCommunity.createQueryBuilder()
.update(DbCommunity)
.set({
communityUuid: communityUuid.data,
authenticatedAt: new Date(),
})
.where({ id: authCom.id })
.execute()
methodLogger.debug('update authCom.uuid successfully')
const homeComB = await getHomeCommunity()
if (homeComB?.communityUuid) {
const responseArgs = new AuthenticationResponseJwtPayloadType(args.handshakeID,homeComB.communityUuid)

View File

@ -6,9 +6,10 @@ import { getLogger } from 'log4js'
// config
import { CONFIG } from './config'
import { LOG4JS_BASE_CATEGORY_NAME } from './config/const'
import { onShutdown, ShutdownReason } from 'shared'
import { onShutdown, printServerCrashAsciiArt, ShutdownReason } from 'shared'
async function main() {
const startTime = new Date()
// init logger
const log4jsConfigFileName = CONFIG.LOG4JS_CONFIG_PLACEHOLDER.replace('%v', CONFIG.FEDERATION_API)
initLogger(
@ -32,7 +33,10 @@ async function main() {
if (ShutdownReason.SIGINT === reason || ShutdownReason.SIGTERM === reason) {
logger.info(`graceful shutdown: ${reason}`)
} else {
logger.error(`crash: ${reason}`, error)
const endTime = new Date()
const duration = endTime.getTime() - startTime.getTime()
printServerCrashAsciiArt(logger, `reason: ${reason}`, `duration: ${duration}ms`, '')
logger.error(error)
}
})
})

View File

@ -1,3 +1,5 @@
import { Logger } from "log4js"
export enum ShutdownReason {
SIGINT = 'SIGINT',
SIGTERM = 'SIGTERM',
@ -38,6 +40,11 @@ export function onShutdown(shutdownHandler: (reason: ShutdownReason, error?: Err
process.emit("SIGINT" as any)
})
}
}
export function printServerCrashAsciiArt(logger: Logger, msg1: string, msg2: string, msg3: string) {
logger.error(` /\\_/\\ ${msg1}`)
logger.error(`( x.x ) ${msg2}`)
logger.error(`> < ${msg3}`)
logger.error('')
}