From 5052f1a508387b384cf38a7ef1023f52190fb34b Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 22 Feb 2023 18:30:59 +1100 Subject: [PATCH 01/15] feat: re-add schema pulling --- spec/SchemaPerformance.spec.js | 49 +++++++++++++++ .../Storage/Mongo/MongoStorageAdapter.js | 11 +++- .../Postgres/PostgresStorageAdapter.js | 8 ++- src/Config.js | 63 +++++++++++++------ src/Controllers/SchemaController.js | 34 ++++++++-- src/Options/Definitions.js | 7 +++ src/Options/docs.js | 1 + src/Options/index.js | 3 + src/ParseServer.js | 1 + 9 files changed, 149 insertions(+), 28 deletions(-) diff --git a/spec/SchemaPerformance.spec.js b/spec/SchemaPerformance.spec.js index 0471871c54..169768d149 100644 --- a/spec/SchemaPerformance.spec.js +++ b/spec/SchemaPerformance.spec.js @@ -204,4 +204,53 @@ describe('Schema Performance', function () { ); expect(getAllSpy.calls.count()).toBe(2); }); + + it('does reload with schemaCacheTTL', async () => { + await reconfigureServer({ + databaseAdapter: undefined, + silent: false, + databaseOptions: { schemaCacheTTL: 1000 }, + }); + const schema = await config.database.loadSchema(); + const spy = spyOn(schema, 'reloadData').and.callThrough(); + Object.defineProperty(spy, 'reloadCalls', { + get: () => spy.calls.all().filter(call => call.args[0].clearCache).length, + }); + + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); + + spy.calls.reset(); + + object.set('foo', 'bar'); + await object.save(); + + expect(spy.reloadCalls).toBe(0); + + await new Promise(resolve => setTimeout(resolve, 1100)); + + object.set('foo', 'bar'); + await object.save(); + + expect(spy.reloadCalls).toBe(1); + }); + + it('cannot set invalid databaseOptions', async () => { + const expectError = async (key, value, expected) => + expectAsync( + reconfigureServer({ databaseAdapter: undefined, databaseOptions: { [key]: value } }) + ).toBeRejectedWith(`databaseOptions.${key} must be a ${expected}`); + for (const databaseOptions of [[], 0, 'string']) { + await expectAsync( + reconfigureServer({ databaseAdapter: undefined, databaseOptions }) + ).toBeRejectedWith(`databaseOptions must be an object`); + } + for (const value of [null, 0, 'string', {}, []]) { + await expectError('enableSchemaHooks', value, 'boolean'); + } + for (const value of [null, false, 'string', {}, []]) { + await expectError('schemaCacheTTL', value, 'number'); + } + }); }); diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index c0d4c0ca9e..f6fd172f61 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -143,7 +143,7 @@ export class MongoStorageAdapter implements StorageAdapter { constructor({ uri = defaults.DefaultMongoURI, collectionPrefix = '', mongoOptions = {} }: any) { this._uri = uri; this._collectionPrefix = collectionPrefix; - this._mongoOptions = mongoOptions; + this._mongoOptions = { ...mongoOptions }; this._mongoOptions.useNewUrlParser = true; this._mongoOptions.useUnifiedTopology = true; this._onchange = () => {}; @@ -152,8 +152,11 @@ export class MongoStorageAdapter implements StorageAdapter { this._maxTimeMS = mongoOptions.maxTimeMS; this.canSortOnJoinTables = true; this.enableSchemaHooks = !!mongoOptions.enableSchemaHooks; - delete mongoOptions.enableSchemaHooks; - delete mongoOptions.maxTimeMS; + this.schemaCacheTTL = mongoOptions.schemaCacheTTL; + for (const key of ['enableSchemaHooks', 'schemaCacheTTL', 'maxTimeMS']) { + delete mongoOptions[key]; + delete this._mongoOptions[key]; + } } watch(callback: () => void): void { @@ -169,6 +172,8 @@ export class MongoStorageAdapter implements StorageAdapter { // encoded const encodedUri = formatUrl(parseUrl(this._uri)); + console.log(this._mongoOptions); + this.connectionPromise = MongoClient.connect(encodedUri, this._mongoOptions) .then(client => { // Starting mongoDB 3.0, the MongoClient.connect don't return a DB anymore but a client diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 444e4e8cca..c1b4c2a008 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -851,10 +851,14 @@ export class PostgresStorageAdapter implements StorageAdapter { _stream: any; _uuid: any; - constructor({ uri, collectionPrefix = '', databaseOptions = {} }: any) { + constructor({ uri, collectionPrefix = '', options = {} }: any) { + const databaseOptions = { ...options }; this._collectionPrefix = collectionPrefix; this.enableSchemaHooks = !!databaseOptions.enableSchemaHooks; - delete databaseOptions.enableSchemaHooks; + this.schemaCacheTTL = databaseOptions.schemaCacheTTL; + for (const key of ['enableSchemaHooks', 'schemaCacheTTL']) { + delete databaseOptions[key]; + } const { client, pgp } = createClient(uri, databaseOptions); this._client = client; diff --git a/src/Config.js b/src/Config.js index bd7c6f21af..7442f4843e 100644 --- a/src/Config.js +++ b/src/Config.js @@ -9,6 +9,7 @@ import DatabaseController from './Controllers/DatabaseController'; import { logLevels as validLogLevels } from './Controllers/LoggerController'; import { AccountLockoutOptions, + DatabaseOptions, FileUploadOptions, IdempotencyOptions, LogLevels, @@ -52,23 +53,20 @@ export class Config { } static put(serverConfiguration) { - Config.validate(serverConfiguration); + Config.validateOptions(serverConfiguration); + Config.validateControllers(serverConfiguration); AppCache.put(serverConfiguration.appId, serverConfiguration); Config.setupPasswordValidator(serverConfiguration.passwordPolicy); return serverConfiguration; } - static validate({ - verifyUserEmails, - userController, - appName, + static validateOptions({ publicServerURL, revokeSessionOnPasswordReset, expireInactiveSessions, sessionLength, defaultLimit, maxLimit, - emailVerifyTokenValidityDuration, accountLockout, passwordPolicy, masterKeyIps, @@ -78,7 +76,6 @@ export class Config { readOnlyMasterKey, allowHeaders, idempotencyOptions, - emailVerifyTokenReuseIfValid, fileUpload, pages, security, @@ -88,6 +85,7 @@ export class Config { allowExpiredAuthDataToken, logLevels, rateLimit, + databaseOptions, }) { if (masterKey === readOnlyMasterKey) { throw new Error('masterKey and readOnlyMasterKey should be different'); @@ -97,17 +95,6 @@ export class Config { throw new Error('masterKey and maintenanceKey should be different'); } - const emailAdapter = userController.adapter; - if (verifyUserEmails) { - this.validateEmailConfiguration({ - emailAdapter, - appName, - publicServerURL, - emailVerifyTokenValidityDuration, - emailVerifyTokenReuseIfValid, - }); - } - this.validateAccountLockoutPolicy(accountLockout); this.validatePasswordPolicy(passwordPolicy); this.validateFileUploadOptions(fileUpload); @@ -136,6 +123,27 @@ export class Config { this.validateRequestKeywordDenylist(requestKeywordDenylist); this.validateRateLimit(rateLimit); this.validateLogLevels(logLevels); + this.validateDatabaseOptions(databaseOptions); + } + + static validateControllers({ + verifyUserEmails, + userController, + appName, + publicServerURL, + emailVerifyTokenValidityDuration, + emailVerifyTokenReuseIfValid, + }) { + const emailAdapter = userController.adapter; + if (verifyUserEmails) { + this.validateEmailConfiguration({ + emailAdapter, + appName, + publicServerURL, + emailVerifyTokenValidityDuration, + emailVerifyTokenReuseIfValid, + }); + } } static validateRequestKeywordDenylist(requestKeywordDenylist) { @@ -526,6 +534,25 @@ export class Config { } } + static validateDatabaseOptions(databaseOptions) { + if (databaseOptions == undefined) { + return; + } + if (Object.prototype.toString.call(databaseOptions) !== '[object Object]') { + throw `databaseOptions must be an object`; + } + if (databaseOptions.enableSchemaHooks === undefined) { + databaseOptions.enableSchemaHooks = DatabaseOptions.enableSchemaHooks.default; + } else if (typeof databaseOptions.enableSchemaHooks !== 'boolean') { + throw `databaseOptions.enableSchemaHooks must be a boolean`; + } + if (databaseOptions.schemaCacheTTL === undefined) { + databaseOptions.schemaCacheTTL = DatabaseOptions.schemaCacheTTL.default; + } else if (typeof databaseOptions.schemaCacheTTL !== 'number') { + throw `databaseOptions.schemaCacheTTL must be a number`; + } + } + static validateRateLimit(rateLimit) { if (!rateLimit) { return; diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 62757d251d..c9b6c22c10 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -694,10 +694,11 @@ export default class SchemaController { constructor(databaseAdapter: StorageAdapter) { this._dbAdapter = databaseAdapter; + const config = Config.get(Parse.applicationId); this.schemaData = new SchemaData(SchemaCache.all(), this.protectedFields); - this.protectedFields = Config.get(Parse.applicationId).protectedFields; + this.protectedFields = config.protectedFields; - const customIds = Config.get(Parse.applicationId).allowCustomObjectId; + const customIds = config.allowCustomObjectId; const customIdRegEx = /^.{1,}$/u; // 1+ chars const autoIdRegEx = /^[a-zA-Z0-9]{1,}$/; @@ -707,6 +708,23 @@ export default class SchemaController { this._dbAdapter.watch(() => { this.reloadData({ clearCache: true }); }); + + this.ttl = { + date: Date.now(), + duration: databaseAdapter.schemaCacheTTL, + }; + } + + async reloadDataIfNeeded() { + const { date, duration } = this.ttl || {}; + if (!duration) { + return; + } + const now = Date.now(); + if (now - date > duration) { + this.ttl.date = now; + await this.reloadData({ clearCache: true }); + } } reloadData(options: LoadSchemaOptions = { clearCache: false }): Promise { @@ -729,10 +747,11 @@ export default class SchemaController { return this.reloadDataPromise; } - getAllClasses(options: LoadSchemaOptions = { clearCache: false }): Promise> { + async getAllClasses(options: LoadSchemaOptions = { clearCache: false }): Promise> { if (options.clearCache) { return this.setAllClasses(); } + await this.reloadDataIfNeeded(); const cached = SchemaCache.all(); if (cached && cached.length) { return Promise.resolve(cached); @@ -1438,9 +1457,14 @@ export default class SchemaController { } // Returns a promise for a new Schema. +let schemaController = null; const load = (dbAdapter: StorageAdapter, options: any): Promise => { - const schema = new SchemaController(dbAdapter); - return schema.reloadData(options).then(() => schema); + if (!schemaController) { + schemaController = new SchemaController(dbAdapter); + } + schemaController._dbAdapter = dbAdapter; + schemaController.ttl.duration = dbAdapter.schemaCacheTTL; + return schemaController.reloadData(options).then(() => schemaController); }; // Builds a new schema (in schema API response format) out of an diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index f7a4f822d7..9210687eb4 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -964,6 +964,13 @@ module.exports.DatabaseOptions = { action: parsers.booleanParser, default: false, }, + schemaCacheTTL: { + env: 'PARSE_SERVER_DATABASE_SCHEMA_CACHE_TTL', + help: + 'The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 5000; set 0 to disable.', + action: parsers.numberParser('schemaCacheTTL'), + default: 5000, + }, }; module.exports.AuthAdapter = { enabled: { diff --git a/src/Options/docs.js b/src/Options/docs.js index b0378d327e..479c784623 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -224,6 +224,7 @@ /** * @interface DatabaseOptions * @property {Boolean} enableSchemaHooks Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. + * @property {Number} schemaCacheTTL The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 5000; set 0 to disable. */ /** diff --git a/src/Options/index.js b/src/Options/index.js index 661d062de6..28dbe711a4 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -543,6 +543,9 @@ export interface DatabaseOptions { /* Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. :DEFAULT: false */ enableSchemaHooks: ?boolean; + /* The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 5000; set 0 to disable. + :DEFAULT: 5000 */ + schemaCacheTTL: ?number; } export interface AuthAdapter { diff --git a/src/ParseServer.js b/src/ParseServer.js index ed21ce12e3..04379ecfd3 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -71,6 +71,7 @@ class ParseServer { Parse.initialize(appId, javascriptKey || 'unused', masterKey); Parse.serverURL = serverURL; + Config.validateOptions(options); const allControllers = controllers.getControllers(options); options.state = 'initialized'; this.config = Config.put(Object.assign({}, options, allControllers)); From e90d568c91c3e843c8f2866102b125a70732f43b Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 22 Feb 2023 18:34:26 +1100 Subject: [PATCH 02/15] Update SchemaController.js --- src/Controllers/SchemaController.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index c9b6c22c10..d37f3f183a 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -716,6 +716,9 @@ export default class SchemaController { } async reloadDataIfNeeded() { + if (this._dbAdapter.enableSchemaHooks) { + return; + } const { date, duration } = this.ttl || {}; if (!duration) { return; From b22148c8cf3c8b75198f97b0359b739d15d1c682 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 22 Feb 2023 18:37:43 +1100 Subject: [PATCH 03/15] Update MongoStorageAdapter.js --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index f6fd172f61..ee70635556 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -172,8 +172,6 @@ export class MongoStorageAdapter implements StorageAdapter { // encoded const encodedUri = formatUrl(parseUrl(this._uri)); - console.log(this._mongoOptions); - this.connectionPromise = MongoClient.connect(encodedUri, this._mongoOptions) .then(client => { // Starting mongoDB 3.0, the MongoClient.connect don't return a DB anymore but a client From c4fe44524fc1dab6213396932914265167fdc989 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 22 Feb 2023 18:47:17 +1100 Subject: [PATCH 04/15] refactor --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 1 + src/Adapters/Storage/Postgres/PostgresStorageAdapter.js | 1 + src/Adapters/Storage/StorageAdapter.js | 2 ++ src/Controllers/SchemaController.js | 3 ++- src/Options/Definitions.js | 3 +-- src/Options/docs.js | 2 +- src/Options/index.js | 3 +-- 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index ee70635556..0a5145bb57 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -139,6 +139,7 @@ export class MongoStorageAdapter implements StorageAdapter { _maxTimeMS: ?number; canSortOnJoinTables: boolean; enableSchemaHooks: boolean; + schemaCacheTTL: ?number; constructor({ uri = defaults.DefaultMongoURI, collectionPrefix = '', mongoOptions = {} }: any) { this._uri = uri; diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index c1b4c2a008..53ad17feac 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -850,6 +850,7 @@ export class PostgresStorageAdapter implements StorageAdapter { _pgp: any; _stream: any; _uuid: any; + schemaCacheTTL: ?number; constructor({ uri, collectionPrefix = '', options = {} }: any) { const databaseOptions = { ...options }; diff --git a/src/Adapters/Storage/StorageAdapter.js b/src/Adapters/Storage/StorageAdapter.js index 6e4573b748..f1fc9f1184 100644 --- a/src/Adapters/Storage/StorageAdapter.js +++ b/src/Adapters/Storage/StorageAdapter.js @@ -30,6 +30,8 @@ export type FullQueryOptions = QueryOptions & UpdateQueryOptions; export interface StorageAdapter { canSortOnJoinTables: boolean; + schemaCacheTTL: ?number; + enableSchemaHooks: boolean; classExists(className: string): Promise; setClassLevelPermissions(className: string, clps: any): Promise; diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index d37f3f183a..ba456062d8 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -691,6 +691,7 @@ export default class SchemaController { reloadDataPromise: ?Promise; protectedFields: any; userIdRegEx: RegExp; + ttl: { [string]: any }; constructor(databaseAdapter: StorageAdapter) { this._dbAdapter = databaseAdapter; @@ -1460,7 +1461,7 @@ export default class SchemaController { } // Returns a promise for a new Schema. -let schemaController = null; +let schemaController: SchemaController; const load = (dbAdapter: StorageAdapter, options: any): Promise => { if (!schemaController) { schemaController = new SchemaController(dbAdapter); diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 9210687eb4..c35ffb3bca 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -967,9 +967,8 @@ module.exports.DatabaseOptions = { schemaCacheTTL: { env: 'PARSE_SERVER_DATABASE_SCHEMA_CACHE_TTL', help: - 'The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 5000; set 0 to disable.', + 'The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production', action: parsers.numberParser('schemaCacheTTL'), - default: 5000, }, }; module.exports.AuthAdapter = { diff --git a/src/Options/docs.js b/src/Options/docs.js index 479c784623..ef8dc7201c 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -224,7 +224,7 @@ /** * @interface DatabaseOptions * @property {Boolean} enableSchemaHooks Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. - * @property {Number} schemaCacheTTL The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 5000; set 0 to disable. + * @property {Number} schemaCacheTTL The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production */ /** diff --git a/src/Options/index.js b/src/Options/index.js index 28dbe711a4..0d3b9778e2 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -543,8 +543,7 @@ export interface DatabaseOptions { /* Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. :DEFAULT: false */ enableSchemaHooks: ?boolean; - /* The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 5000; set 0 to disable. - :DEFAULT: 5000 */ + /* The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production */ schemaCacheTTL: ?number; } From 73c2e34e40d134c93d82e9195341853fd1029b16 Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 23 Feb 2023 10:37:34 +1100 Subject: [PATCH 05/15] refactor --- spec/SchemaPerformance.spec.js | 4 ++-- src/Controllers/SchemaController.js | 23 +++++++++-------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/spec/SchemaPerformance.spec.js b/spec/SchemaPerformance.spec.js index 169768d149..d1eaf4b7c3 100644 --- a/spec/SchemaPerformance.spec.js +++ b/spec/SchemaPerformance.spec.js @@ -211,8 +211,8 @@ describe('Schema Performance', function () { silent: false, databaseOptions: { schemaCacheTTL: 1000 }, }); - const schema = await config.database.loadSchema(); - const spy = spyOn(schema, 'reloadData').and.callThrough(); + const SchemaController = require('../lib/Controllers/SchemaController').SchemaController; + const spy = spyOn(SchemaController.prototype, 'reloadData').and.callThrough(); Object.defineProperty(spy, 'reloadCalls', { get: () => spy.calls.all().filter(call => call.args[0].clearCache).length, }); diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index ba456062d8..63fa7d1a62 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -682,6 +682,10 @@ const typeToString = (type: SchemaField | string): string => { } return `${type.type}`; }; +const ttl = { + date: Date.now(), + duration: undefined, +}; // Stores the entire schema of the app in a weird hybrid format somewhere between // the mongo format and the Parse format. Soon, this will all be Parse format. @@ -691,7 +695,6 @@ export default class SchemaController { reloadDataPromise: ?Promise; protectedFields: any; userIdRegEx: RegExp; - ttl: { [string]: any }; constructor(databaseAdapter: StorageAdapter) { this._dbAdapter = databaseAdapter; @@ -710,23 +713,20 @@ export default class SchemaController { this.reloadData({ clearCache: true }); }); - this.ttl = { - date: Date.now(), - duration: databaseAdapter.schemaCacheTTL, - }; + ttl.duration = databaseAdapter.schemaCacheTTL; } async reloadDataIfNeeded() { if (this._dbAdapter.enableSchemaHooks) { return; } - const { date, duration } = this.ttl || {}; + const { date, duration } = ttl || {}; if (!duration) { return; } const now = Date.now(); if (now - date > duration) { - this.ttl.date = now; + ttl.date = now; await this.reloadData({ clearCache: true }); } } @@ -1461,14 +1461,9 @@ export default class SchemaController { } // Returns a promise for a new Schema. -let schemaController: SchemaController; const load = (dbAdapter: StorageAdapter, options: any): Promise => { - if (!schemaController) { - schemaController = new SchemaController(dbAdapter); - } - schemaController._dbAdapter = dbAdapter; - schemaController.ttl.duration = dbAdapter.schemaCacheTTL; - return schemaController.reloadData(options).then(() => schemaController); + const schema = new SchemaController(dbAdapter); + return schema.reloadData(options).then(() => schema); }; // Builds a new schema (in schema API response format) out of an From b29bcd09bba38b7f52f2cc56006d2c37158390ff Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 23 Feb 2023 11:07:30 +1100 Subject: [PATCH 06/15] Update SchemaPerformance.spec.js --- spec/SchemaPerformance.spec.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/SchemaPerformance.spec.js b/spec/SchemaPerformance.spec.js index d1eaf4b7c3..c1ab173e5e 100644 --- a/spec/SchemaPerformance.spec.js +++ b/spec/SchemaPerformance.spec.js @@ -206,8 +206,13 @@ describe('Schema Performance', function () { }); it('does reload with schemaCacheTTL', async () => { + const databaseURI = + process.env.PARSE_SERVER_TEST_DB === 'postgres' + ? 'postgres://localhost:5432/parse_server_postgres_adapter_test_database' + : 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; await reconfigureServer({ databaseAdapter: undefined, + databaseURI, silent: false, databaseOptions: { schemaCacheTTL: 1000 }, }); From dfd581b3945fd512fed1356a660f78bc28887480 Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 23 Feb 2023 11:45:25 +1100 Subject: [PATCH 07/15] postgres --- spec/SchemaPerformance.spec.js | 5 ++--- src/Controllers/SchemaController.js | 3 +-- src/Controllers/index.js | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/spec/SchemaPerformance.spec.js b/spec/SchemaPerformance.spec.js index c1ab173e5e..cd02f93c86 100644 --- a/spec/SchemaPerformance.spec.js +++ b/spec/SchemaPerformance.spec.js @@ -207,9 +207,8 @@ describe('Schema Performance', function () { it('does reload with schemaCacheTTL', async () => { const databaseURI = - process.env.PARSE_SERVER_TEST_DB === 'postgres' - ? 'postgres://localhost:5432/parse_server_postgres_adapter_test_database' - : 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; + process.env.PARSE_SERVER_TEST_DATABASE_URI || + 'postgres://localhost:5432/parse_server_postgres_adapter_test_database'; await reconfigureServer({ databaseAdapter: undefined, databaseURI, diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 63fa7d1a62..2ced2d186a 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -712,8 +712,6 @@ export default class SchemaController { this._dbAdapter.watch(() => { this.reloadData({ clearCache: true }); }); - - ttl.duration = databaseAdapter.schemaCacheTTL; } async reloadDataIfNeeded() { @@ -1463,6 +1461,7 @@ export default class SchemaController { // Returns a promise for a new Schema. const load = (dbAdapter: StorageAdapter, options: any): Promise => { const schema = new SchemaController(dbAdapter); + ttl.duration = dbAdapter.schemaCacheTTL; return schema.reloadData(options).then(() => schema); }; diff --git a/src/Controllers/index.js b/src/Controllers/index.js index 0a9b3db57d..6885b1c056 100644 --- a/src/Controllers/index.js +++ b/src/Controllers/index.js @@ -238,7 +238,7 @@ export function getDatabaseAdapter(databaseURI, collectionPrefix, databaseOption return new PostgresStorageAdapter({ uri: databaseURI, collectionPrefix, - databaseOptions, + options: databaseOptions, }); default: return new MongoStorageAdapter({ From 61b64b366d274a45fad411b35f66aa22d8913bac Mon Sep 17 00:00:00 2001 From: dblythy Date: Thu, 23 Feb 2023 12:01:43 +1100 Subject: [PATCH 08/15] refactor --- spec/SchemaPerformance.spec.js | 5 +++-- src/Adapters/Storage/Postgres/PostgresStorageAdapter.js | 8 ++++---- src/Controllers/index.js | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/spec/SchemaPerformance.spec.js b/spec/SchemaPerformance.spec.js index cd02f93c86..7cd488771e 100644 --- a/spec/SchemaPerformance.spec.js +++ b/spec/SchemaPerformance.spec.js @@ -207,8 +207,9 @@ describe('Schema Performance', function () { it('does reload with schemaCacheTTL', async () => { const databaseURI = - process.env.PARSE_SERVER_TEST_DATABASE_URI || - 'postgres://localhost:5432/parse_server_postgres_adapter_test_database'; + process.env.PARSE_SERVER_TEST_DB === 'postgres' + ? process.env.PARSE_SERVER_TEST_DATABASE_URI + : 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; await reconfigureServer({ databaseAdapter: undefined, databaseURI, diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 53ad17feac..55aef0913c 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -852,16 +852,16 @@ export class PostgresStorageAdapter implements StorageAdapter { _uuid: any; schemaCacheTTL: ?number; - constructor({ uri, collectionPrefix = '', options = {} }: any) { - const databaseOptions = { ...options }; + constructor({ uri, collectionPrefix = '', databaseOptions = {} }: any) { + const options = { ...databaseOptions }; this._collectionPrefix = collectionPrefix; this.enableSchemaHooks = !!databaseOptions.enableSchemaHooks; this.schemaCacheTTL = databaseOptions.schemaCacheTTL; for (const key of ['enableSchemaHooks', 'schemaCacheTTL']) { - delete databaseOptions[key]; + delete options[key]; } - const { client, pgp } = createClient(uri, databaseOptions); + const { client, pgp } = createClient(uri, options); this._client = client; this._onchange = () => {}; this._pgp = pgp; diff --git a/src/Controllers/index.js b/src/Controllers/index.js index 6885b1c056..0a9b3db57d 100644 --- a/src/Controllers/index.js +++ b/src/Controllers/index.js @@ -238,7 +238,7 @@ export function getDatabaseAdapter(databaseURI, collectionPrefix, databaseOption return new PostgresStorageAdapter({ uri: databaseURI, collectionPrefix, - options: databaseOptions, + databaseOptions, }); default: return new MongoStorageAdapter({ From 1a8579661a2e831b93f21b1046706c4058ddecf6 Mon Sep 17 00:00:00 2001 From: dblythy Date: Sun, 26 Feb 2023 10:37:02 +1100 Subject: [PATCH 09/15] camel case --- spec/SchemaPerformance.spec.js | 6 +++--- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 6 +++--- src/Adapters/Storage/Postgres/PostgresStorageAdapter.js | 6 +++--- src/Adapters/Storage/StorageAdapter.js | 2 +- src/Config.js | 8 ++++---- src/Controllers/SchemaController.js | 2 +- src/Options/Definitions.js | 4 ++-- src/Options/docs.js | 2 +- src/Options/index.js | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/spec/SchemaPerformance.spec.js b/spec/SchemaPerformance.spec.js index 7cd488771e..17238b0ed6 100644 --- a/spec/SchemaPerformance.spec.js +++ b/spec/SchemaPerformance.spec.js @@ -205,7 +205,7 @@ describe('Schema Performance', function () { expect(getAllSpy.calls.count()).toBe(2); }); - it('does reload with schemaCacheTTL', async () => { + it('does reload with schemaCacheTtl', async () => { const databaseURI = process.env.PARSE_SERVER_TEST_DB === 'postgres' ? process.env.PARSE_SERVER_TEST_DATABASE_URI @@ -214,7 +214,7 @@ describe('Schema Performance', function () { databaseAdapter: undefined, databaseURI, silent: false, - databaseOptions: { schemaCacheTTL: 1000 }, + databaseOptions: { schemaCacheTtl: 1000 }, }); const SchemaController = require('../lib/Controllers/SchemaController').SchemaController; const spy = spyOn(SchemaController.prototype, 'reloadData').and.callThrough(); @@ -255,7 +255,7 @@ describe('Schema Performance', function () { await expectError('enableSchemaHooks', value, 'boolean'); } for (const value of [null, false, 'string', {}, []]) { - await expectError('schemaCacheTTL', value, 'number'); + await expectError('schemaCacheTtl', value, 'number'); } }); }); diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 0a5145bb57..78833a026b 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -139,7 +139,7 @@ export class MongoStorageAdapter implements StorageAdapter { _maxTimeMS: ?number; canSortOnJoinTables: boolean; enableSchemaHooks: boolean; - schemaCacheTTL: ?number; + schemaCacheTtl: ?number; constructor({ uri = defaults.DefaultMongoURI, collectionPrefix = '', mongoOptions = {} }: any) { this._uri = uri; @@ -153,8 +153,8 @@ export class MongoStorageAdapter implements StorageAdapter { this._maxTimeMS = mongoOptions.maxTimeMS; this.canSortOnJoinTables = true; this.enableSchemaHooks = !!mongoOptions.enableSchemaHooks; - this.schemaCacheTTL = mongoOptions.schemaCacheTTL; - for (const key of ['enableSchemaHooks', 'schemaCacheTTL', 'maxTimeMS']) { + this.schemaCacheTtl = mongoOptions.schemaCacheTtl; + for (const key of ['enableSchemaHooks', 'schemaCacheTtl', 'maxTimeMS']) { delete mongoOptions[key]; delete this._mongoOptions[key]; } diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 55aef0913c..82ac0c20dc 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -850,14 +850,14 @@ export class PostgresStorageAdapter implements StorageAdapter { _pgp: any; _stream: any; _uuid: any; - schemaCacheTTL: ?number; + schemaCacheTtl: ?number; constructor({ uri, collectionPrefix = '', databaseOptions = {} }: any) { const options = { ...databaseOptions }; this._collectionPrefix = collectionPrefix; this.enableSchemaHooks = !!databaseOptions.enableSchemaHooks; - this.schemaCacheTTL = databaseOptions.schemaCacheTTL; - for (const key of ['enableSchemaHooks', 'schemaCacheTTL']) { + this.schemaCacheTtl = databaseOptions.schemaCacheTtl; + for (const key of ['enableSchemaHooks', 'schemaCacheTtl']) { delete options[key]; } diff --git a/src/Adapters/Storage/StorageAdapter.js b/src/Adapters/Storage/StorageAdapter.js index f1fc9f1184..7605784a43 100644 --- a/src/Adapters/Storage/StorageAdapter.js +++ b/src/Adapters/Storage/StorageAdapter.js @@ -30,7 +30,7 @@ export type FullQueryOptions = QueryOptions & UpdateQueryOptions; export interface StorageAdapter { canSortOnJoinTables: boolean; - schemaCacheTTL: ?number; + schemaCacheTtl: ?number; enableSchemaHooks: boolean; classExists(className: string): Promise; diff --git a/src/Config.js b/src/Config.js index 7442f4843e..7a934de31b 100644 --- a/src/Config.js +++ b/src/Config.js @@ -546,10 +546,10 @@ export class Config { } else if (typeof databaseOptions.enableSchemaHooks !== 'boolean') { throw `databaseOptions.enableSchemaHooks must be a boolean`; } - if (databaseOptions.schemaCacheTTL === undefined) { - databaseOptions.schemaCacheTTL = DatabaseOptions.schemaCacheTTL.default; - } else if (typeof databaseOptions.schemaCacheTTL !== 'number') { - throw `databaseOptions.schemaCacheTTL must be a number`; + if (databaseOptions.schemaCacheTtl === undefined) { + databaseOptions.schemaCacheTtl = DatabaseOptions.schemaCacheTtl.default; + } else if (typeof databaseOptions.schemaCacheTtl !== 'number') { + throw `databaseOptions.schemaCacheTtl must be a number`; } } diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 2ced2d186a..ad3699aaa5 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -1461,7 +1461,7 @@ export default class SchemaController { // Returns a promise for a new Schema. const load = (dbAdapter: StorageAdapter, options: any): Promise => { const schema = new SchemaController(dbAdapter); - ttl.duration = dbAdapter.schemaCacheTTL; + ttl.duration = dbAdapter.schemaCacheTtl; return schema.reloadData(options).then(() => schema); }; diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index c35ffb3bca..707b29d8aa 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -964,11 +964,11 @@ module.exports.DatabaseOptions = { action: parsers.booleanParser, default: false, }, - schemaCacheTTL: { + schemaCacheTtl: { env: 'PARSE_SERVER_DATABASE_SCHEMA_CACHE_TTL', help: 'The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production', - action: parsers.numberParser('schemaCacheTTL'), + action: parsers.numberParser('schemaCacheTtl'), }, }; module.exports.AuthAdapter = { diff --git a/src/Options/docs.js b/src/Options/docs.js index ef8dc7201c..9bc6a44d88 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -224,7 +224,7 @@ /** * @interface DatabaseOptions * @property {Boolean} enableSchemaHooks Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. - * @property {Number} schemaCacheTTL The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production + * @property {Number} schemaCacheTtl The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production */ /** diff --git a/src/Options/index.js b/src/Options/index.js index 0d3b9778e2..981c3b2962 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -544,7 +544,7 @@ export interface DatabaseOptions { :DEFAULT: false */ enableSchemaHooks: ?boolean; /* The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production */ - schemaCacheTTL: ?number; + schemaCacheTtl: ?number; } export interface AuthAdapter { From 963dcdd206de186f0601cf9ab21bc8f3a5edaa87 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:53:02 +0100 Subject: [PATCH 10/15] Update src/Options/docs.js Signed-off-by: Manuel <5673677+mtrezza@users.noreply.github.com> --- src/Options/docs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Options/docs.js b/src/Options/docs.js index a297571d31..6e3ec713a7 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -225,7 +225,7 @@ /** * @interface DatabaseOptions * @property {Boolean} enableSchemaHooks Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. - * @property {Number} schemaCacheTtl The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production + * @property {Number} schemaCacheTtl The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. By default this option is disabled and the schema cache never expires. */ /** From 9240ce50b6bd101e4a1c88bb33a2b5294488f005 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:53:08 +0100 Subject: [PATCH 11/15] Update src/Options/index.js Signed-off-by: Manuel <5673677+mtrezza@users.noreply.github.com> --- src/Options/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Options/index.js b/src/Options/index.js index 2fb9420df4..d67a5ad47e 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -548,7 +548,7 @@ export interface DatabaseOptions { /* Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. :DEFAULT: false */ enableSchemaHooks: ?boolean; - /* The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production */ + /* The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. By default this option is disabled and the schema cache never expires. */ schemaCacheTtl: ?number; } From b04f294b26ed7aba303329f8ceb80199add87c6f Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:53:13 +0100 Subject: [PATCH 12/15] Update src/Options/Definitions.js Signed-off-by: Manuel <5673677+mtrezza@users.noreply.github.com> --- src/Options/Definitions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 5a34275f8b..2b0d31afcd 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -974,7 +974,7 @@ module.exports.DatabaseOptions = { schemaCacheTtl: { env: 'PARSE_SERVER_DATABASE_SCHEMA_CACHE_TTL', help: - 'The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production', + 'The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. By default this option is disabled and the schema cache never expires.', action: parsers.numberParser('schemaCacheTtl'), }, }; From bbfbe8b6f45e5e2e40b5bbe3c5fc1d2528f607ac Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:57:36 +0100 Subject: [PATCH 13/15] Update src/Options/index.js Signed-off-by: Manuel <5673677+mtrezza@users.noreply.github.com> --- src/Options/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Options/index.js b/src/Options/index.js index d67a5ad47e..778374e7e7 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -548,7 +548,7 @@ export interface DatabaseOptions { /* Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. :DEFAULT: false */ enableSchemaHooks: ?boolean; - /* The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. By default this option is disabled and the schema cache never expires. */ + /* The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. Default is infinite which means the schema cache never expires. */ schemaCacheTtl: ?number; } From cd2181517bf3ab60c98406119eeea39a9b308466 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:57:42 +0100 Subject: [PATCH 14/15] Update src/Options/docs.js Signed-off-by: Manuel <5673677+mtrezza@users.noreply.github.com> --- src/Options/docs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Options/docs.js b/src/Options/docs.js index 6e3ec713a7..0eb6488c74 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -225,7 +225,7 @@ /** * @interface DatabaseOptions * @property {Boolean} enableSchemaHooks Enables database real-time hooks to update single schema cache. Set to `true` if using multiple Parse Servers instances connected to the same database. Failing to do so will cause a schema change to not propagate to all instances and re-syncing will only happen when the instances restart. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. - * @property {Number} schemaCacheTtl The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. By default this option is disabled and the schema cache never expires. + * @property {Number} schemaCacheTtl The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. Default is infinite which means the schema cache never expires. */ /** From 8c72debe35014666d79975cbbdd05ddeb9b67b11 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:57:48 +0100 Subject: [PATCH 15/15] Update src/Options/Definitions.js Signed-off-by: Manuel <5673677+mtrezza@users.noreply.github.com> --- src/Options/Definitions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 2b0d31afcd..a25e69c70a 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -974,7 +974,7 @@ module.exports.DatabaseOptions = { schemaCacheTtl: { env: 'PARSE_SERVER_DATABASE_SCHEMA_CACHE_TTL', help: - 'The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. By default this option is disabled and the schema cache never expires.', + 'The duration in seconds after which the schema cache expires and will be refetched from the database. Use this option if using multiple Parse Servers instances connected to the same database. A low duration will cause the schema cache to be updated too often, causing unnecessary database reads. A high duration will cause the schema to be updated too rarely, increasing the time required until schema changes propagate to all server instances. This feature can be used as an alternative or in conjunction with the option `enableSchemaHooks`. Default is infinite which means the schema cache never expires.', action: parsers.numberParser('schemaCacheTtl'), }, };