void TimeoutController::runTimeouts(TimePoint time) { auto now = Clock::now(); // Make sure we don't skip some events if function was run before actual time. if (time < now) { time = now; } if (nextTimeout_ > time) { return; } nextTimeout_ = TimePoint::max(); for (auto& bucket : timeoutHandleBuckets_) { auto& list = bucket.second; for (auto it = list.begin(); it != list.end();) { if (it->timeout_ > time) { nextTimeout_ = std::min(nextTimeout_, it->timeout_); break; } it->onTimeout(); it = list.erase(it); } } if (nextTimeout_ != TimePoint::max()) { scheduleRun(); } }
void Work::complete(CompleteResult result) { CLOG(DEBUG, "Work") << "completed " << getUniqueName(); auto& succ = mApp.getMetrics().NewMeter({"work", "unit", "success"}, "unit"); auto& fail = mApp.getMetrics().NewMeter({"work", "unit", "failure"}, "unit"); switch (result) { case WORK_COMPLETE_OK: setState(onSuccess()); break; case WORK_COMPLETE_FAILURE: setState(WORK_FAILURE_RETRY); break; case WORK_COMPLETE_FATAL: setState(WORK_FAILURE_FATAL); break; } switch (getState()) { case WORK_SUCCESS: succ.Mark(); CLOG(DEBUG, "Work") << "notifying parent of successful " << getUniqueName(); notifyParent(); break; case WORK_FAILURE_RETRY: fail.Mark(); onFailureRetry(); scheduleRetry(); break; case WORK_FAILURE_RAISE: case WORK_FAILURE_FATAL: fail.Mark(); onFailureRaise(); CLOG(DEBUG, "Work") << "notifying parent of failed " << getUniqueName(); notifyParent(); break; case WORK_PENDING: succ.Mark(); advance(); break; case WORK_RUNNING: succ.Mark(); scheduleRun(); break; default: assert(false); break; } }
void Work::advance() { if (getState() != WORK_PENDING) { return; } CLOG(DEBUG, "Work") << "advancing " << getUniqueName(); advanceChildren(); if (allChildrenSuccessful()) { CLOG(DEBUG, "Work") << "all " << mChildren.size() << " children of " << getUniqueName() << " successful, scheduling run"; scheduleRun(); } else if (anyChildFatalFailure()) { CLOG(DEBUG, "Work") << "some of " << mChildren.size() << " children of " << getUniqueName() << " fatally failed, scheduling " << "fatal failure"; scheduleFatalFailure(); } else if (anyChildRaiseFailure()) { CLOG(DEBUG, "Work") << "some of " << mChildren.size() << " children of " << getUniqueName() << " failed, scheduling failure"; scheduleFailure(); } }
void TimeoutController::runTimeouts(TimePoint time) { auto now = Clock::now(); // Make sure we don't skip some events if function was run before actual time. if (time < now) { time = now; } if (nextTimeout_ > time) { return; } nextTimeout_ = TimePoint::max(); for (auto& bucket : timeoutHandleBuckets_) { auto& list = *bucket.second; while (!list.empty()) { if (!list.front().canceled) { if (list.front().timeout > time) { nextTimeout_ = std::min(nextTimeout_, list.front().timeout); break; } list.front().func(); } list.pop(); } } if (nextTimeout_ != TimePoint::max()) { scheduleRun(); } }
intptr_t TimeoutController::registerTimeout( std::function<void()> f, Duration duration) { auto& list = [&]() -> TimeoutHandleList& { for (auto& bucket : timeoutHandleBuckets_) { if (bucket.first == duration) { return *bucket.second; } } timeoutHandleBuckets_.emplace_back( duration, std::make_unique<TimeoutHandleList>()); return *timeoutHandleBuckets_.back().second; }(); auto timeout = Clock::now() + duration; list.emplace(std::move(f), timeout, list); if (timeout < nextTimeout_) { nextTimeout_ = timeout; scheduleRun(); } return reinterpret_cast<intptr_t>(&list.back()); }
void TimeoutController::registerTimeout(TimeoutHandle& th, Duration duration) { auto& list = [&]() -> TimeoutHandleList& { for (auto& bucket : timeoutHandleBuckets_) { if (bucket.first == duration) { return bucket.second; } } timeoutHandleBuckets_.emplace_back(duration, TimeoutHandleList()); return timeoutHandleBuckets_.back().second; }(); list.push_back(th); th.timeout_ = Clock::now() + duration; if (th.timeout_ < nextTimeout_) { nextTimeout_ = th.timeout_; scheduleRun(); } }