Skip to content

Instantly share code, notes, and snippets.

@TheRusskiy
Last active October 31, 2021 17:15
Show Gist options
  • Save TheRusskiy/94a767ff0e6b5116c3b22f266b655829 to your computer and use it in GitHub Desktop.
Save TheRusskiy/94a767ff0e6b5116c3b22f266b655829 to your computer and use it in GitHub Desktop.
Typeorm - migrations with advisory lock
import { migrateDatabase } from './typeormMigrationUtills'
;(async () => {
await migrateDatabase()
})()
import { syncDatabase } from './typeormMigrationUtills'
;(async () => {
await syncDatabase()
})()
import { Connection, createConnection } from 'typeorm'
import config from '../ormconfig'
import CRC32 from 'crc-32'
const MIGRATOR_SALT = 2053462845
async function withAdvisoryLock(
connection: Connection,
callback: () => Promise<void>
): Promise<boolean> {
// generate a unique lock name, has to be an integer
const lockName = CRC32.str(config.database as string) * MIGRATOR_SALT
let lock = false
try {
// try to acquire a lock
const [{ pg_try_advisory_lock: locked }]: [
{ pg_try_advisory_lock: boolean }
] = await connection.manager.query(
`SELECT pg_try_advisory_lock(${lockName})`
)
lock = locked
// if already locked, print a warning an exit
if (!lock) {
console.warn(`Failed to get advisory lock: ${lockName}`)
return false
}
// execute our code inside the lock
await callback()
return true
} finally {
// if we acquired a lock, we need to unlock it
if (lock) {
const [{ pg_advisory_unlock: wasLocked }]: [
{ pg_advisory_unlock: boolean }
] = await connection.manager.query(
`SELECT pg_advisory_unlock(${lockName})`
)
if (!wasLocked) {
console.warn(`Advisory lock was not locked: ${lockName}`)
}
}
}
}
export async function migrateDatabase() {
const connection = await createConnection({ ...config, logging: true })
await withAdvisoryLock(connection, async () => {
await connection.runMigrations({
transaction: 'all'
})
})
await connection.close()
}
export async function syncDatabase() {
const connection = await createConnection({ ...config, logging: true })
await withAdvisoryLock(connection, async () => {
await connection.synchronize()
})
await connection.close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment