Commit a7fbf225 authored by AdamSimpson's avatar AdamSimpson
Browse files
parents f7d86579 0c8782f1
Loading
Loading
Loading
Loading
+4 −7
Original line number Diff line number Diff line
@@ -12,29 +12,26 @@ 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;

    // Hold reservations that are to be fulfilled
    std::list<Reservation> reservations;

    // List of currently available builders
    std::set<Builder> available_builders;

    // Maximum number of active and cached builders
    const std::size_t max_builders;

    // 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
+42 −42
Original line number Diff line number Diff line
@@ -7,57 +7,57 @@ 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());
                            }

            // If the reservation is complete delete the builder
            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
    std::set<Builder> available_builders;
    std::set_difference(all_builders.begin(), all_builders.end(),
                        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();
    // Assign builders to any pending reservations
    for (auto &reservation : reservations) {
        if (reservation.pending() && !available_builders.empty()) {
            reservation.ready(*available_builders.begin());
            available_builders.erase(available_builders.begin());
        }
    }

    // Request new builders if slots are open
    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--;
                    });
    }

}
 No newline at end of file
+1 −4
Original line number Diff line number Diff line
@@ -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());
                            }