Added new service ProfileActivityService
Maintains a timestamp of when each profile was last active on the server. Timestamp is refreshed on two events: `game/start and `game/keepalive` Timestamp is used to determine if a profiles hideout should be processed. If a profile has a timestamp older than 90 minutes, it is not processed. (could be set lower but its a conservative value) This has the side effects of not adjusting the `sptUpdateLastRunTimestamp` property, resulting in `saveProfile()` not running for every profile. My testing shows a 20x perf increase for every profile in SPT not in use. Service could likely be used in other scenarios to avoid doing unnecessary work
This commit is contained in:
parent
73a1dd9511
commit
a9d89695f0
@ -7,5 +7,6 @@
|
|||||||
},
|
},
|
||||||
"expCraftAmount": 10,
|
"expCraftAmount": 10,
|
||||||
"overrideCraftTimeSeconds": -1,
|
"overrideCraftTimeSeconds": -1,
|
||||||
"overrideBuildTimeSeconds": -1
|
"overrideBuildTimeSeconds": -1,
|
||||||
|
"updateProfileHideoutWhenActiveWithinMinutes": 90
|
||||||
}
|
}
|
@ -39,6 +39,7 @@ import { GiftService } from "@spt-aki/services/GiftService";
|
|||||||
import { ItemBaseClassService } from "@spt-aki/services/ItemBaseClassService";
|
import { ItemBaseClassService } from "@spt-aki/services/ItemBaseClassService";
|
||||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||||
import { OpenZoneService } from "@spt-aki/services/OpenZoneService";
|
import { OpenZoneService } from "@spt-aki/services/OpenZoneService";
|
||||||
|
import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService";
|
||||||
import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService";
|
import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService";
|
||||||
import { RaidTimeAdjustmentService } from "@spt-aki/services/RaidTimeAdjustmentService";
|
import { RaidTimeAdjustmentService } from "@spt-aki/services/RaidTimeAdjustmentService";
|
||||||
import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService";
|
import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService";
|
||||||
@ -78,6 +79,7 @@ export class GameController
|
|||||||
@inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService,
|
@inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService,
|
||||||
@inject("GiftService") protected giftService: GiftService,
|
@inject("GiftService") protected giftService: GiftService,
|
||||||
@inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService,
|
@inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService,
|
||||||
|
@inject("ProfileActivityService") protected profileActivityService: ProfileActivityService,
|
||||||
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
)
|
)
|
||||||
@ -109,6 +111,8 @@ export class GameController
|
|||||||
// Store client start time in app context
|
// Store client start time in app context
|
||||||
this.applicationContext.addValue(ContextVariableType.CLIENT_START_TIMESTAMP, startTimeStampMS);
|
this.applicationContext.addValue(ContextVariableType.CLIENT_START_TIMESTAMP, startTimeStampMS);
|
||||||
|
|
||||||
|
this.profileActivityService.setActivityTimestamp(sessionID);
|
||||||
|
|
||||||
if (this.coreConfig.fixes.fixShotgunDispersion)
|
if (this.coreConfig.fixes.fixShotgunDispersion)
|
||||||
{
|
{
|
||||||
this.fixShotgunDispersions();
|
this.fixShotgunDispersions();
|
||||||
@ -504,6 +508,7 @@ export class GameController
|
|||||||
*/
|
*/
|
||||||
public getKeepAlive(sessionId: string): IGameKeepAliveResponse
|
public getKeepAlive(sessionId: string): IGameKeepAliveResponse
|
||||||
{
|
{
|
||||||
|
this.profileActivityService.setActivityTimestamp(sessionId);
|
||||||
return { msg: "OK", utc_time: new Date().getTime() / 1000 };
|
return { msg: "OK", utc_time: new Date().getTime() / 1000 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ import { SaveServer } from "@spt-aki/servers/SaveServer";
|
|||||||
import { FenceService } from "@spt-aki/services/FenceService";
|
import { FenceService } from "@spt-aki/services/FenceService";
|
||||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||||
import { PlayerService } from "@spt-aki/services/PlayerService";
|
import { PlayerService } from "@spt-aki/services/PlayerService";
|
||||||
|
import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService";
|
||||||
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
||||||
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
||||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||||
@ -79,6 +80,7 @@ export class HideoutController
|
|||||||
@inject("HideoutHelper") protected hideoutHelper: HideoutHelper,
|
@inject("HideoutHelper") protected hideoutHelper: HideoutHelper,
|
||||||
@inject("ScavCaseRewardGenerator") protected scavCaseRewardGenerator: ScavCaseRewardGenerator,
|
@inject("ScavCaseRewardGenerator") protected scavCaseRewardGenerator: ScavCaseRewardGenerator,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
|
@inject("ProfileActivityService") protected profileActivityService: ProfileActivityService,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
@inject("FenceService") protected fenceService: FenceService,
|
@inject("FenceService") protected fenceService: FenceService,
|
||||||
@ -1323,7 +1325,13 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
for (const sessionID in this.saveServer.getProfiles())
|
for (const sessionID in this.saveServer.getProfiles())
|
||||||
{
|
{
|
||||||
if ("Hideout" in this.saveServer.getProfile(sessionID).characters.pmc)
|
if (
|
||||||
|
"Hideout" in this.saveServer.getProfile(sessionID).characters.pmc
|
||||||
|
&& this.profileActivityService.activeWithinLastMinutes(
|
||||||
|
sessionID,
|
||||||
|
this.hideoutConfig.updateProfileHideoutWhenActiveWithinMinutes,
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
this.hideoutHelper.updatePlayerHideout(sessionID);
|
this.hideoutHelper.updatePlayerHideout(sessionID);
|
||||||
}
|
}
|
||||||
|
@ -213,6 +213,7 @@ import { OpenZoneService } from "@spt-aki/services/OpenZoneService";
|
|||||||
import { PaymentService } from "@spt-aki/services/PaymentService";
|
import { PaymentService } from "@spt-aki/services/PaymentService";
|
||||||
import { PlayerService } from "@spt-aki/services/PlayerService";
|
import { PlayerService } from "@spt-aki/services/PlayerService";
|
||||||
import { PmcChatResponseService } from "@spt-aki/services/PmcChatResponseService";
|
import { PmcChatResponseService } from "@spt-aki/services/PmcChatResponseService";
|
||||||
|
import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService";
|
||||||
import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService";
|
import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService";
|
||||||
import { ProfileSnapshotService } from "@spt-aki/services/ProfileSnapshotService";
|
import { ProfileSnapshotService } from "@spt-aki/services/ProfileSnapshotService";
|
||||||
import { RagfairCategoriesService } from "@spt-aki/services/RagfairCategoriesService";
|
import { RagfairCategoriesService } from "@spt-aki/services/RagfairCategoriesService";
|
||||||
@ -747,6 +748,10 @@ export class Container
|
|||||||
depContainer.register<GiftService>("GiftService", GiftService);
|
depContainer.register<GiftService>("GiftService", GiftService);
|
||||||
depContainer.register<MailSendService>("MailSendService", MailSendService);
|
depContainer.register<MailSendService>("MailSendService", MailSendService);
|
||||||
depContainer.register<RaidTimeAdjustmentService>("RaidTimeAdjustmentService", RaidTimeAdjustmentService);
|
depContainer.register<RaidTimeAdjustmentService>("RaidTimeAdjustmentService", RaidTimeAdjustmentService);
|
||||||
|
|
||||||
|
depContainer.register<ProfileActivityService>("ProfileActivityService", ProfileActivityService, {
|
||||||
|
lifecycle: Lifecycle.Singleton,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static registerServers(depContainer: DependencyContainer): void
|
private static registerServers(depContainer: DependencyContainer): void
|
||||||
|
@ -11,4 +11,6 @@ export interface IHideoutConfig extends IBaseConfig
|
|||||||
expCraftAmount: number;
|
expCraftAmount: number;
|
||||||
overrideCraftTimeSeconds: number;
|
overrideCraftTimeSeconds: number;
|
||||||
overrideBuildTimeSeconds: number;
|
overrideBuildTimeSeconds: number;
|
||||||
|
/** Only process a profiles hideout crafts when it has been active in the last x minutes */
|
||||||
|
updateProfileHideoutWhenActiveWithinMinutes: number;
|
||||||
}
|
}
|
||||||
|
36
project/src/services/ProfileActivityService.ts
Normal file
36
project/src/services/ProfileActivityService.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { injectable } from "tsyringe";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class ProfileActivityService
|
||||||
|
{
|
||||||
|
protected profileActivityTimestamps: Record<string, number> = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was the requested profile active in the last requested minutes
|
||||||
|
* @param sessionId Profile to check
|
||||||
|
* @param minutes Minutes to check for activity in
|
||||||
|
* @returns True when profile was active within past x minutes
|
||||||
|
*/
|
||||||
|
public activeWithinLastMinutes(sessionId: string, minutes: number): boolean
|
||||||
|
{
|
||||||
|
const currentTimestamp = new Date().getTime() / 1000;
|
||||||
|
const storedActivityTimestamp = this.profileActivityTimestamps[sessionId];
|
||||||
|
if (!storedActivityTimestamp)
|
||||||
|
{
|
||||||
|
// No value, no assumed activity (server offline?)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// True if difference since last timestamp to now is below desired amount
|
||||||
|
return (currentTimestamp - storedActivityTimestamp) < (minutes * 60); // convert minutes to seconds to compare
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the timestamp a profile was last observed active
|
||||||
|
* @param sessionId Profile to update
|
||||||
|
*/
|
||||||
|
public setActivityTimestamp(sessionId: string): void
|
||||||
|
{
|
||||||
|
this.profileActivityTimestamps[sessionId] = new Date().getTime() / 1000;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user