func (p *RedisPacer) CanBid(campaign rtb.Campaign) bool { id := campaign.Id() key := p.paceAccountKey(campaign.Id()) // Update remaining budget every time to compensate for unspent bids last cycle cpi := rtb.MicroCentsPerImpression(campaign.BidCpmInMicroCents()) budget := p.banker.RemainingDailyBudgetInMicroCents(id) // Account not yet configured, or they actually have no budget. The pacer is not needed. if budget == 0 || cpi == 0 { return true // Allow it to pass and configure it } now := time.Now().UTC() midnight := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 0, 0, time.UTC) // TODO: This definitely only needs to be calculated at the end of each segment. Not every time we request a bid. durationToMidnight := midnight.Sub(now) segmentsToMidnight := int64(durationToMidnight / p.segment) remaining := (budget / cpi) / segmentsToMidnight remainingBudget, err := p.da.DebitIfNotZero(key, 1, remaining, time.Now().UTC().Add(p.segment)) // fmt.Printf("Campign: %v, Bids Per Segment: %v, Segment: %v, Remaining Budget: %v\n", id, remaining, p.segment, remainingBudget) if err == nil { return remainingBudget > 0 } else { return false } }
// highestBidder Returns the highest bidder with available funds. // campaigns must be in order from highest CPM to lowest // Caller is committed to using the campaign returned by this func (b *BidRequestBidder) highestBidder(campaigns []rtb.Campaign) (campaign rtb.Campaign, remainingDailyBudgetInMicroCents int64) { for _, campaign := range campaigns { id := campaign.Id() if b.Pacer == nil || b.Pacer.CanBid(campaign) { bid := campaign.BidCpmInMicroCents() if remainingDailyBudgetInMicroCents, err := b.CampaignProvider.DebitCampaign(id, rtb.MicroCentsPerImpression(bid), b.dailyBudgetExpirationTime); err == nil { return campaign, remainingDailyBudgetInMicroCents } } } return nil, 0 }