Loading BuilderQueue/include/BuilderQueue.h +4 −4 Original line number Diff line number Diff line Loading @@ -12,14 +12,14 @@ public: explicit BuilderQueue(asio::io_service &io_service) : io_service(io_service), max_builders(1), max_available_builders(max_builders), update_in_progress(false) pending_requests(0) {} // Create a new queue reservation and return it to the requester Reservation& enter(); // Attempt to process the queue after an event that adds/removes builders or requests void tick(); void tick(asio::yield_context yield); private: asio::io_service &io_service; Loading @@ -35,6 +35,6 @@ private: // Maximum number of builders to spin and keep up in reserve const std::size_t max_available_builders; // Flag to determine if an update is already in progress bool update_in_progress; // Number of build requests that have been submitted but not processed by OpenStack yet int pending_requests; }; No newline at end of file BuilderQueue/src/BuilderQueue.cpp +42 −44 Original line number Diff line number Diff line Loading @@ -7,41 +7,30 @@ Reservation &BuilderQueue::enter() { return reservations.back(); } void BuilderQueue::tick() { // Process pending reservations for (auto &reservation : reservations) { if (reservation.pending() && !available_builders.empty()) { reservation.ready(*available_builders.begin()); available_builders.erase(available_builders.begin()); } } // Update OpenStack by creating and removing builders as required // This section can take quite some time so is done in a coroutine if (!update_in_progress) { update_in_progress = true; asio::spawn(io_service, [&](asio::yield_context yield) { void BuilderQueue::tick(asio::yield_context yield) { // Update list of "Active" OpenStack builders auto all_builders = OpenStackBuilder::get_builders(io_service, yield); std::set<Builder> unavailable_builders; // Update reservation information // Process reservations for (auto &reservation : reservations) { // Set unavailable builders, that is builders which are attached to a reservation if (reservation.builder) { unavailable_builders.insert(reservation.builder.get()); } // Delete builders that are complete if (reservation.complete()) { asio::spawn(io_service, [&](asio::yield_context yield) { OpenStackBuilder::destroy(reservation.builder.get(), io_service, yield); }; reservation.builder = boost::none; }); } } // TODO handle error state builders - potentially in destroy script? // Remove all completed reservations reservations.remove_if([](const auto &res) { return res.complete(); // Delete reservations that are completed and don't have an active builder associated with them reservations.remove_if([](const auto &reservation) { return reservation.complete() && !reservation.builder; }); // Available_builders = all_builders - unavailable_builders Loading @@ -49,15 +38,24 @@ void BuilderQueue::tick() { unavailable_builders.begin(), unavailable_builders.end(), std::inserter(available_builders, available_builders.begin())); // Spin up builders so we have the requested available auto open_slots = max_builders - all_builders.size(); auto open_available_slots = max_available_builders - available_builders.size(); // Request new builders to fill up "reserve" auto open_slots = max_builders - all_builders.size() - pending_requests; auto open_available_slots = max_available_builders - available_builders.size() - pending_requests; auto request_count = std::min(open_slots, open_available_slots); for (auto i = 0; i < request_count; i++) { pending_requests++; asio::spawn(io_service, [&](asio::yield_context yield) { OpenStackBuilder::request_create(io_service, yield); } update_in_progress = false; pending_requests--; }); } // Process pending reservations for (auto &reservation : reservations) { if (reservation.pending() && !available_builders.empty()) { reservation.ready(*available_builders.begin()); available_builders.erase(available_builders.begin()); } } } No newline at end of file BuilderQueue/src/main.cpp +1 −4 Original line number Diff line number Diff line Loading @@ -36,14 +36,11 @@ int main(int argc, char *argv[]) { }); // Start the queue which ticks at the specified interval boost::asio::deadline_timer timer(io_service); asio::spawn(io_service, [&](asio::yield_context yield) { for (;;) { try { builder_queue.tick(); timer.expires_from_now(boost::posix_time::seconds(1)); timer.async_wait(yield); builder_queue.tick(yield); } catch (std::exception &e) { logger::write(std::string() + "Queue tick error: " + e.what()); } Loading Loading
BuilderQueue/include/BuilderQueue.h +4 −4 Original line number Diff line number Diff line Loading @@ -12,14 +12,14 @@ public: explicit BuilderQueue(asio::io_service &io_service) : io_service(io_service), max_builders(1), max_available_builders(max_builders), update_in_progress(false) pending_requests(0) {} // Create a new queue reservation and return it to the requester Reservation& enter(); // Attempt to process the queue after an event that adds/removes builders or requests void tick(); void tick(asio::yield_context yield); private: asio::io_service &io_service; Loading @@ -35,6 +35,6 @@ private: // Maximum number of builders to spin and keep up in reserve const std::size_t max_available_builders; // Flag to determine if an update is already in progress bool update_in_progress; // Number of build requests that have been submitted but not processed by OpenStack yet int pending_requests; }; No newline at end of file
BuilderQueue/src/BuilderQueue.cpp +42 −44 Original line number Diff line number Diff line Loading @@ -7,41 +7,30 @@ Reservation &BuilderQueue::enter() { return reservations.back(); } void BuilderQueue::tick() { // Process pending reservations for (auto &reservation : reservations) { if (reservation.pending() && !available_builders.empty()) { reservation.ready(*available_builders.begin()); available_builders.erase(available_builders.begin()); } } // Update OpenStack by creating and removing builders as required // This section can take quite some time so is done in a coroutine if (!update_in_progress) { update_in_progress = true; asio::spawn(io_service, [&](asio::yield_context yield) { void BuilderQueue::tick(asio::yield_context yield) { // Update list of "Active" OpenStack builders auto all_builders = OpenStackBuilder::get_builders(io_service, yield); std::set<Builder> unavailable_builders; // Update reservation information // Process reservations for (auto &reservation : reservations) { // Set unavailable builders, that is builders which are attached to a reservation if (reservation.builder) { unavailable_builders.insert(reservation.builder.get()); } // Delete builders that are complete if (reservation.complete()) { asio::spawn(io_service, [&](asio::yield_context yield) { OpenStackBuilder::destroy(reservation.builder.get(), io_service, yield); }; reservation.builder = boost::none; }); } } // TODO handle error state builders - potentially in destroy script? // Remove all completed reservations reservations.remove_if([](const auto &res) { return res.complete(); // Delete reservations that are completed and don't have an active builder associated with them reservations.remove_if([](const auto &reservation) { return reservation.complete() && !reservation.builder; }); // Available_builders = all_builders - unavailable_builders Loading @@ -49,15 +38,24 @@ void BuilderQueue::tick() { unavailable_builders.begin(), unavailable_builders.end(), std::inserter(available_builders, available_builders.begin())); // Spin up builders so we have the requested available auto open_slots = max_builders - all_builders.size(); auto open_available_slots = max_available_builders - available_builders.size(); // Request new builders to fill up "reserve" auto open_slots = max_builders - all_builders.size() - pending_requests; auto open_available_slots = max_available_builders - available_builders.size() - pending_requests; auto request_count = std::min(open_slots, open_available_slots); for (auto i = 0; i < request_count; i++) { pending_requests++; asio::spawn(io_service, [&](asio::yield_context yield) { OpenStackBuilder::request_create(io_service, yield); } update_in_progress = false; pending_requests--; }); } // Process pending reservations for (auto &reservation : reservations) { if (reservation.pending() && !available_builders.empty()) { reservation.ready(*available_builders.begin()); available_builders.erase(available_builders.begin()); } } } No newline at end of file
BuilderQueue/src/main.cpp +1 −4 Original line number Diff line number Diff line Loading @@ -36,14 +36,11 @@ int main(int argc, char *argv[]) { }); // Start the queue which ticks at the specified interval boost::asio::deadline_timer timer(io_service); asio::spawn(io_service, [&](asio::yield_context yield) { for (;;) { try { builder_queue.tick(); timer.expires_from_now(boost::posix_time::seconds(1)); timer.async_wait(yield); builder_queue.tick(yield); } catch (std::exception &e) { logger::write(std::string() + "Queue tick error: " + e.what()); } Loading