Create Import Locks

This commit is contained in:
zkldi
2021-06-16 13:25:52 +01:00
parent cf35e9cb98
commit d417ea8a4b
5 changed files with 57 additions and 3 deletions
+3 -3
View File
@@ -80,7 +80,7 @@ dependencies:
rate-limit-redis: 2.1.0
redis: 3.1.2
rimraf: 3.0.2
tachi-common: github.com/zkldi/tachi-common/137fb72499a2ee6a98791ffea3961d0c69bf24b7
tachi-common: github.com/zkldi/tachi-common/fff6217ee6c483f773fed97848802a774e8c5b70
typescript: 4.3.2
winston: 3.3.3
@@ -4445,8 +4445,8 @@ packages:
engines: {node: '>=6'}
dev: true
github.com/zkldi/tachi-common/137fb72499a2ee6a98791ffea3961d0c69bf24b7:
resolution: {tarball: https://codeload.github.com/zkldi/tachi-common/tar.gz/137fb72499a2ee6a98791ffea3961d0c69bf24b7}
github.com/zkldi/tachi-common/fff6217ee6c483f773fed97848802a774e8c5b70:
resolution: {tarball: https://codeload.github.com/zkldi/tachi-common/tar.gz/fff6217ee6c483f773fed97848802a774e8c5b70}
name: kamaitachi-common
version: 0.1.0
dependencies:
+2
View File
@@ -24,6 +24,7 @@ import {
PBScoreDocument,
UserMilestoneDocument,
BMSCourseDocument,
ImportLockDocument,
} from "tachi-common";
import monk from "monk";
import { MONGO_BASE_URL } from "../../lib/setup/config";
@@ -132,6 +133,7 @@ const db = {
"bms-course-lookup": monkDB.get<BMSCourseDocument>("bms-course-lookup"),
"api-tokens": monkDB.get<APITokenDocument>("api-tokens"),
"orphan-scores": monkDB.get<OrphanScoreDocument>("orphan-scores"),
"import-locks": monkDB.get<ImportLockDocument>("import-locks"),
};
export default db;
@@ -0,0 +1,32 @@
import db from "../../../../external/mongo/db";
import { integer } from "tachi-common";
/**
* Gets a users "import lock" if one exists. If one does not exist, it is set.
* @param userID - The user this import lock is for.
* @returns If no lock exists for this user (and one was created), undefined is returned
* If a lock exists for the user, the lock is returned.
*/
export function GetOrSetUserLock(userID: integer) {
return db["import-locks"].findOneAndUpdate(
{
userID,
},
{
userID,
},
{
upsert: true,
returnDocument: "before",
}
);
}
/**
* Removes a users import lock.
*/
export function RemoveUserLock(userID: integer) {
return db["import-locks"].remove({
userID,
});
}
@@ -22,6 +22,8 @@ import { ConverterFunction, ImportInputParser } from "../import-types/common/typ
import { ScorePlaytypeMap } from "./common/types";
import { Converters } from "../import-types/converters";
import { ClassHandler } from "./user-game-stats/types";
import { GetOrSetUserLock, RemoveUserLock } from "./import-locks/lock";
import ScoreImportFatalError from "./score-importing/score-import-error";
/**
* Performs a Score Import.
@@ -33,6 +35,21 @@ export default async function ScoreImportMain<D, C>(
InputParser: ImportInputParser<D, C>,
providedImportObjects?: { logger: KtLogger; importID: string }
) {
const lock = await GetOrSetUserLock(user.id);
if (lock) {
// @danger
// Throwing away an import if the user already has one outgoing is *bad*, as in the case
// of degraded performance we might just start throwing scores away. This is obviously
// not great, but any other solution involves making a queue, which can't be done because
// InputParser is a very dynamic function that cannot be stored in redis or something.
//
// Under normal circumstances, there is no scenario where a user would have two ongoing
// imports at the same time - even if they were using single-score imports on a 5 second
// chart, as each score import takes only around ~10-15miliseconds.
throw new ScoreImportFatalError(409, "This user already has an ongoing import.");
}
const timeStarted = Date.now();
let importID;
let logger;
@@ -202,6 +219,8 @@ export default async function ScoreImportMain<D, C>(
},
});
await RemoveUserLock(user.id);
return ImportDocument;
}
@@ -0,0 +1 @@
[]