(core) Enforce daily limit on API usage

Summary:
Keep track of the number of API requests made for this document today in redis. Uses local caches of the count and the document so that usually requests can proceed without waiting for redis or the database.

Moved the free standing function apiThrottle to become a method to avoid adding another layer of request handler callbacks.

Test Plan: Added a DocApi test

Reviewers: paulfitz

Reviewed By: paulfitz

Subscribers: dsagal

Differential Revision: https://phab.getgrist.com/D3327
This commit is contained in:
Alex Hall
2022-03-21 22:22:35 +02:00
parent b6f146d755
commit 2c9ae6dc94
4 changed files with 131 additions and 35 deletions

View File

@@ -133,6 +133,10 @@ class DummyDocWorkerMap implements IDocWorkerMap {
public async getDocGroup(docId: string): Promise<string|null> {
return null;
}
public incrementDocApiUsage(key: string): Promise<number> {
return Promise.resolve(0);
}
}
/**
@@ -507,6 +511,18 @@ 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]);
}
/**
* Fetch the doc-<docId> hash and doc-<docId>-checksum key from redis.
* Return as a decoded DocStatus and a checksum.