import { Campaign, ChoiceRequest, CampaignGroup } from "../../models"; import { StepResult } from "../stepResult"; import constants from "../../utils/constants"; import { AbstractStep } from "../abstractStep"; import SpeedService from "../../services/speed.service"; const jStat = require("jstat"); export default class SpeedThresholdStep extends AbstractStep { constructor(readonly speedService: SpeedService) { super("speed_threshold"); this.autoPassCampaignGroup = CampaignGroup.Marketplace | CampaignGroup.Fallback; } async run(request: ChoiceRequest): Promise { const result: StepResult = new StepResult(); const selected: Campaign[] = []; const supplyPrioScoreActive = this.featureConfigService.getBooleanValue( request, constants.SUPPLY_PRIO_SCORE_ACTIVE_PARAM, false ); if (supplyPrioScoreActive) { this.speedService.addPrioScoreMetadata(request); } const supplyPrioScore = request.metadata.supply_obj_prio_score ?? 0; const maxDelay = this.featureConfigService.getFloatValue( request, constants.MAX_DELAY_PARAM, 1.5 ); const stddevRandomNoise = this.featureConfigService.getFloatValue( request, constants.RANDOM_NOISE_COMPOSITE_SCORE_SPEED_PARAM, 0 ); const norm = new jStat.normal(0, stddevRandomNoise); // SpeedService.addSpeedMetadata should have been called beforehand request.campaigns.forEach((c) => { const compositeScore = c.metadata.composite_score; const speedThreshold = c.metadata.speed_threshold; const delay = c.metadata.delay; if (delay != null && maxDelay && delay > maxDelay) { return; } if ( speedThreshold == null || compositeScore == null || compositeScore + supplyPrioScore + norm.sample() >= speedThreshold ) { selected.push(c); } }); result.passCampaigns(...selected); return result; } }