mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
perf: Add Model.replica getter for opt-in read replica queries
Allows Sequelize ORM queries to explicitly opt-in to using the read replica connection via a static getter on the base Model class. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import type {
|
||||
SaveOptions,
|
||||
} from "sequelize";
|
||||
import { DataTypes, UniqueConstraintError } from "sequelize";
|
||||
import type { Sequelize } from "sequelize-typescript";
|
||||
import {
|
||||
AfterCreate,
|
||||
AfterDestroy,
|
||||
@@ -27,6 +28,12 @@ import type { Replace, APIContext } from "@server/types";
|
||||
import { getChangsetSkipped } from "../decorators/Changeset";
|
||||
import { InternalError } from "@server/errors";
|
||||
|
||||
/**
|
||||
* Lazy reference to the read-only Sequelize instance.
|
||||
* Imported dynamically to avoid circular dependencies.
|
||||
*/
|
||||
let _sequelizeReadOnly: Sequelize | undefined;
|
||||
|
||||
type EventOverrideOptions = {
|
||||
/** Override the default event name. */
|
||||
name?: string;
|
||||
@@ -56,6 +63,30 @@ class Model<
|
||||
*/
|
||||
static eventNamespace: string | undefined;
|
||||
|
||||
/**
|
||||
* Returns this model bound to the read-only database connection (read replica).
|
||||
* Use this for queries that can tolerate slight replication lag and don't need
|
||||
* to read-your-writes consistency.
|
||||
*
|
||||
* @example
|
||||
* // Opt-in to read replica
|
||||
* const documents = await Document.replica.findAll({ where: { teamId } });
|
||||
*
|
||||
* // Default behavior uses primary
|
||||
* const document = await Document.findOne({ where: { id } });
|
||||
*
|
||||
* @returns the model bound to the read replica connection.
|
||||
*/
|
||||
static get replica(): typeof this {
|
||||
if (!_sequelizeReadOnly) {
|
||||
// Lazy import to avoid circular dependencies
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
_sequelizeReadOnly =
|
||||
require("@server/storage/database").sequelizeReadOnly;
|
||||
}
|
||||
return _sequelizeReadOnly!.models[this.name] as typeof this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates this instance, and if the validation passes, persists it to the database.
|
||||
*/
|
||||
|
||||
@@ -256,13 +256,9 @@ export const sequelize = createDatabaseInstance(databaseConfig, models);
|
||||
* Falls back to the main connection if DATABASE_URL_READ_ONLY is not set.
|
||||
*/
|
||||
export const sequelizeReadOnly = env.DATABASE_URL_READ_ONLY
|
||||
? createDatabaseInstance(
|
||||
env.DATABASE_URL_READ_ONLY,
|
||||
{},
|
||||
{
|
||||
readOnly: true,
|
||||
}
|
||||
)
|
||||
? createDatabaseInstance(env.DATABASE_URL_READ_ONLY, models, {
|
||||
readOnly: true,
|
||||
})
|
||||
: sequelize;
|
||||
|
||||
export const migrations = createMigrationRunner(sequelize, [
|
||||
|
||||
Reference in New Issue
Block a user