mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Add flexibility to daily API usage limit
Summary: Allow exceeding the daily API usage limit for a doc based on additional allocations for the current hour and minute. See the doc comment on getDocApiUsageKeysToIncr for details. This means that up to 5 redis keys may be relevant at a time for a single document. Test Plan: Updated and expanded 'Daily API Limit' tests. Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D3368
This commit is contained in:
@@ -43,6 +43,11 @@ export const teamFreeFeatures: Features = {
|
||||
gracePeriodDays: 14,
|
||||
};
|
||||
|
||||
export const testDailyApiLimitFeatures = {
|
||||
...teamFreeFeatures,
|
||||
baseMaxApiUnitsPerDocumentPerDay: 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* A summary of features used in unrestricted grandfathered accounts, and also
|
||||
* in some test settings.
|
||||
@@ -87,7 +92,7 @@ export interface IProduct {
|
||||
* TODO: change capitalization of name of grandfather product.
|
||||
*
|
||||
*/
|
||||
const PRODUCTS: IProduct[] = [
|
||||
export const PRODUCTS: IProduct[] = [
|
||||
// This is a product for grandfathered accounts/orgs.
|
||||
{
|
||||
name: 'Free',
|
||||
@@ -166,7 +171,9 @@ export class Product extends BaseEntity {
|
||||
* If `apply` is set, the products are changed in the db, otherwise
|
||||
* the are left unchanged. A summary of affected products is returned.
|
||||
*/
|
||||
export async function synchronizeProducts(connection: Connection, apply: boolean): Promise<string[]> {
|
||||
export async function synchronizeProducts(
|
||||
connection: Connection, apply: boolean, products = PRODUCTS
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
await connection.query('select name, features, stripe_product_id from products limit 1');
|
||||
} catch (e) {
|
||||
@@ -175,7 +182,7 @@ export async function synchronizeProducts(connection: Connection, apply: boolean
|
||||
}
|
||||
const changingProducts: string[] = [];
|
||||
await connection.transaction(async transaction => {
|
||||
const desiredProducts = new Map(PRODUCTS.map(p => [p.name, p]));
|
||||
const desiredProducts = new Map(products.map(p => [p.name, p]));
|
||||
const existingProducts = new Map((await transaction.find(Product))
|
||||
.map(p => [p.name, p]));
|
||||
for (const product of desiredProducts.values()) {
|
||||
|
||||
@@ -137,8 +137,8 @@ class DummyDocWorkerMap implements IDocWorkerMap {
|
||||
return null;
|
||||
}
|
||||
|
||||
public incrementDocApiUsage(key: string): Promise<number> {
|
||||
return Promise.resolve(0);
|
||||
public getRedisClient(): RedisClient {
|
||||
throw new Error("No redis client here");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,16 +517,8 @@ export class DocWorkerMap implements IDocWorkerMap {
|
||||
return this._client.getAsync(`doc-${docId}-group`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the value at the given redis key representing API usage of one document in one day.
|
||||
* Expire the key after a day just so that it cleans itself up.
|
||||
* Returns the value after incrementing.
|
||||
* This is not related to other responsibilities of this class,
|
||||
* but this class conveniently manages the redis client.
|
||||
*/
|
||||
public async incrementDocApiUsage(key: string): Promise<number | null> {
|
||||
const result = await this._client.multi().incr(key).expire(key, 24 * 60 * 60).execAsync();
|
||||
return Number(result?.[0]);
|
||||
public getRedisClient(): RedisClient {
|
||||
return this._client;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user