![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* test_agent.h -*- C++ -*- 00002 Jeremy Banres, 27 November 2012 00003 Copyright (c) 2012 Datacratic Inc. All rights reserved. 00004 00005 Test for an agent. 00006 */ 00007 00008 #pragma once 00009 00010 #include "rtbkit/plugins/bidding_agent/bidding_agent.h" 00011 #include "jml/arch/futex.h" 00012 00013 namespace RTBKIT { 00014 00015 struct TestAgent : public RTBKIT::BiddingAgent { 00016 TestAgent(std::shared_ptr<RTBKIT::ServiceProxies> proxies, 00017 const std::string & name = "testAgent") 00018 : RTBKIT::BiddingAgent(proxies, name) 00019 { 00020 setDefaultConfig(); 00021 setupCallbacks(); 00022 clear(); 00023 } 00024 00025 RTBKIT::AgentConfig config; 00026 00027 void setDefaultConfig() 00028 { 00029 RTBKIT::AgentConfig config; 00030 config.account = {"testCampaign", "testStrategy"}; 00031 config.maxInFlight = 20000; 00032 config.creatives.push_back(RTBKIT::Creative::sampleLB); 00033 config.creatives.push_back(RTBKIT::Creative::sampleWS); 00034 config.creatives.push_back(RTBKIT::Creative::sampleBB); 00035 00036 this->config = config; 00037 } 00038 00039 void start() 00040 { 00041 BiddingAgent::start(); 00042 configure(); 00043 } 00044 00045 void clear() 00046 { 00047 numHeartbeats = numBidRequests = numErrors = numGotConfig = 0; 00048 numWins = numLosses = numNoBudgets = numTooLates = 0; 00049 numBidsOutstanding = 0; 00050 } 00051 00052 bool sleepUntilIdle(double waitTime = 0.0) 00053 { 00054 Date timeout; 00055 if (waitTime > 0.0) timeout = Date::now().plusSeconds(waitTime); 00056 00057 for (;;) { 00058 int oldOutstanding = numBidsOutstanding; 00059 00060 //cerr << "numBidsOutstanding = " << oldOutstanding << endl; 00061 00062 if (oldOutstanding == 0) return true; 00063 00064 Date now = Date::now(); 00065 if (now >= timeout && waitTime != 0.0) return false; 00066 00067 int res; 00068 00069 if (waitTime == 0) 00070 res = ML::futex_wait(numBidsOutstanding, oldOutstanding); 00071 else res = ML::futex_wait(numBidsOutstanding, oldOutstanding, 00072 now.secondsUntil(timeout)); 00073 00074 //cerr << "res = " << res << endl; 00075 00076 if (res == 0) return true; 00077 if (errno == ETIMEDOUT) return false; 00078 if (errno == EINTR) continue; 00079 if (errno == EAGAIN) continue; 00080 00081 throw ML::Exception(errno, "futex_wait"); 00082 } 00083 } 00084 00085 int numHeartbeats; 00086 int numBidRequests; 00087 int numErrors; 00088 int numGotConfig; 00089 int numWins; 00090 int numLosses; 00091 int numNoBudgets; 00092 int numTooLates; 00093 00094 typedef ML::Spinlock Lock; 00095 typedef boost::lock_guard<Lock> Guard; 00096 mutable Lock lock; 00097 00098 std::set<Id> awaitingStatus; 00099 int numBidsOutstanding; 00100 00101 void defaultError(double timestamp, const std::string & error, 00102 const std::vector<std::string> & message) 00103 { 00104 using namespace std; 00105 cerr << "agent got error: " << error << " from message: " 00106 << message << endl; 00107 __sync_fetch_and_add(&numErrors, 1); 00108 } 00109 00110 void finishBid(int & counter, const RTBKIT::BidResult & args) 00111 { 00112 __sync_fetch_and_add(&counter, 1); 00113 Guard guard(lock); 00114 if (!awaitingStatus.erase(args.auctionId)) 00115 throw ML::Exception("couldn't find in progress auction"); 00116 00117 numBidsOutstanding = awaitingStatus.size(); 00118 if (numBidsOutstanding == 0) 00119 ML::futex_wake(numBidsOutstanding); 00120 } 00121 00122 void defaultWin(const RTBKIT::BidResult & args) 00123 { 00124 finishBid(numWins, args); 00125 //cerr << args.accountInfo << endl; 00126 } 00127 00128 void defaultLoss(const RTBKIT::BidResult & args) 00129 { 00130 finishBid(numLosses, args); 00131 } 00132 00133 void defaultNoBudget(const RTBKIT::BidResult & args) 00134 { 00135 finishBid(numNoBudgets, args); 00136 } 00137 00138 void defaultTooLate(const RTBKIT::BidResult & args) 00139 { 00140 finishBid(numTooLates, args); 00141 } 00142 00143 void doBid(const Id & id, 00144 const Bids & bids, 00145 const Json::Value & metadata) 00146 { 00147 if (bids.size() != 0) 00148 recordBid(id); 00149 RTBKIT::BiddingAgent::doBid(id, bids, metadata); 00150 } 00151 00152 void bidNull(double timestamp, 00153 const Id & id, 00154 std::shared_ptr<RTBKIT::BidRequest> br, 00155 const Bids & bids, 00156 double timeLeftMs, 00157 const Json::Value & augmentations) 00158 { 00159 using namespace std; 00160 //cerr << "got auction " << id << endl; 00161 doBid(id, bids, Json::Value()); 00162 __sync_fetch_and_add(&numBidRequests, 1); 00163 } 00164 00165 void recordBid(const Id & id) 00166 { 00167 Guard guard(lock); 00168 if (!awaitingStatus.insert(id).second) 00169 throw ML::Exception("auction already in progress"); 00170 00171 numBidsOutstanding = awaitingStatus.size(); 00172 } 00173 00174 void setupCallbacks() 00175 { 00176 onError 00177 = boost::bind(&TestAgent::defaultError, this, _1, _2, _3); 00178 onBidRequest 00179 = boost::bind(&TestAgent::bidNull, this, _1, _2, _3, _4, _5, _6); 00180 onWin 00181 = boost::bind(&TestAgent::defaultWin, this, _1); 00182 onLoss 00183 = boost::bind(&TestAgent::defaultLoss, this, _1); 00184 onNoBudget 00185 = boost::bind(&TestAgent::defaultNoBudget, this, _1); 00186 onTooLate 00187 = boost::bind(&TestAgent::defaultTooLate, this, _1); 00188 } 00189 00190 void configure() 00191 { 00192 doConfig(config); 00193 } 00194 00195 }; 00196 00197 } // namespace RTBKIT