55#include <QMutexLocker>
122 LOG(VB_GENERAL, LOG_DEBUG, QString(
"%1 Running? %2/In window? %3.")
145 LOG(VB_GENERAL, LOG_INFO, QString(
"Running HouseKeeperTask '%1'.")
150 LOG(VB_GENERAL, LOG_WARNING, QString(
"HouseKeeperTask '%1' already "
151 "running. Refusing to run concurrently").arg(
m_dbTag));
160 LOG(VB_GENERAL, LOG_INFO, QString(
"HouseKeeperTask '%1' Failed.")
165 LOG(VB_GENERAL, LOG_INFO,
166 QString(
"HouseKeeperTask '%1' Finished Successfully.")
199 query.
prepare(
"SELECT lastrun,lastsuccess FROM housekeeping"
201 " AND hostname IS NULL");
205 query.
prepare(
"SELECT lastrun,lastsuccess FROM housekeeping"
207 " AND hostname = :HOST");
238 query.
prepare(
"UPDATE `housekeeping` SET `lastrun`=:TIME,"
239 " `lastsuccess`=:STIME"
240 " WHERE `tag` = :TAG"
241 " AND `hostname` IS NULL");
245 query.
prepare(
"UPDATE `housekeeping` SET `lastrun`=:TIME,"
246 " `lastsuccess`=:STIME"
247 " WHERE `tag` = :TAG"
248 " AND `hostname` = :HOST");
263 LOG(VB_GENERAL, LOG_DEBUG, QString(
"%1: UPDATEd %2 run time.")
271 query.
prepare(
"INSERT INTO `housekeeping`"
272 " (`tag`, `lastrun`, `lastsuccess`)"
273 " VALUES (:TAG, :TIME, :STIME)");
277 query.
prepare(
"INSERT INTO `housekeeping`"
278 " (`tag`, `hostname`, `lastrun`, `lastsuccess`)"
279 " VALUES (:TAG, :HOST, :TIME, :STIME)");
291 LOG(VB_GENERAL, LOG_DEBUG, QString(
"%1: INSERTed %2 run time.")
298 msg = QString(
"HOUSE_KEEPER_SUCCESSFUL %1 %2 %3");
300 msg = QString(
"HOUSE_KEEPER_RUNNING %1 %2 %3");
333 std::chrono::seconds period,
float min,
float max, std::chrono::seconds retry,
336 m_windowPercent(min, max)
345 std::chrono::seconds period =
m_period;
382 auto elapsed = std::chrono::seconds(
GetLastRun().secsTo(now));
397 double prob = 1.0 - (duration_cast<floatsecs>(elapsed -
m_windowElapsed.first) /
413 bool res = (rand() > (int)(prob2 *
static_cast<double>(RAND_MAX)));
426 auto elapsed = std::chrono::seconds(
GetLastRun().secsTo(now));
457 m_windowHour(0h, 23h)
463 std::chrono::hours minhour, std::chrono::hours maxhour,
466 m_windowHour(minhour, maxhour)
486 LOG(VB_GENERAL, LOG_DEBUG, QString(
"%1 Run window between %2 - %3.")
503 auto hour = std::chrono::hours(now.time().hour());
582 : m_timer(new QTimer(this))
612 for (
auto *it : std::as_const(
m_taskMap))
634 QMap<QString,HouseKeeperTask*>::iterator it =
m_taskMap.begin();
646 QString tag = task->
GetTag();
650 LOG(VB_GENERAL, LOG_ERR,
651 QString(
"HouseKeeperTask '%1' already registered. "
652 "Rejecting duplicate.").arg(tag));
656 LOG(VB_GENERAL, LOG_INFO,
657 QString(
"Registering HouseKeeperTask '%1'.").arg(tag));
687 query.
prepare(
"SELECT `tag`,`lastrun`"
688 " FROM `housekeeping`"
689 " WHERE `hostname` = :HOST"
690 " OR `hostname` IS NULL");
700 QString tag = query.
value(0).toString();
712 if ((*it)->CheckImmediate())
715 (*it)->UpdateLastRun();
718 else if ((*it)->CheckStartup())
721 LOG(VB_GENERAL, LOG_INFO,
722 QString(
"Queueing HouseKeeperTask '%1'.").arg(it.key()));
729 LOG(VB_GENERAL, LOG_INFO,
"Starting HouseKeeper.");
736 LOG(VB_GENERAL, LOG_DEBUG,
"Running HouseKeeper.");
743 if ((*it)->CheckRun(now))
746 LOG(VB_GENERAL, LOG_INFO,
747 QString(
"Queueing HouseKeeperTask '%1'.").arg(it.key()));
768 if ((*it)->isRunning())
780 LOG(VB_GENERAL, LOG_DEBUG,
781 QString(
"Discarded HouseKeepingThreads have completed and "
782 "been deleted. Current count %1 -> %2.")
783 .arg(count1).arg(count2));
809 LOG(VB_GENERAL, LOG_DEBUG,
"Running initial HouseKeepingThread.");
820 LOG(VB_GENERAL, LOG_DEBUG,
821 QString(
"Current HouseKeepingThread is delayed on task, "
822 "spawning replacement. Current count %1.")
833 LOG(VB_GENERAL, LOG_DEBUG,
"Waking HouseKeepingThread.");
845 if ((me->Message().left(20) ==
"HOUSE_KEEPER_RUNNING") ||
846 (me->Message().left(23) ==
"HOUSE_KEEPER_SUCCESSFUL"))
848 QStringList tokens = me->
Message()
849 .split(
" ", Qt::SkipEmptyParts);
850 if (tokens.size() != 4)
853 const QString&
hostname = tokens[1];
854 const QString& tag = tokens[2];
856 bool successful = me->Message().contains(
"SUCCESSFUL");
868 m_taskMap[tag]->SetLastRun(last, successful);
DailyHouseKeeperTask(const QString &dbTag, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
virtual void SetHourWindow(std::chrono::hours min, std::chrono::hours max)
bool InWindow(const QDateTime &now) override
QPair< std::chrono::hours, std::chrono::hours > m_windowHour
void CalculateWindow(void) override
Definition for a single task to be run by the HouseKeeper.
QDateTime QueryLastSuccess(void)
QDateTime QueryLastRun(void)
bool CheckImmediate(void)
QDateTime GetLastRun(void)
bool CheckRun(const QDateTime &now)
QDateTime UpdateLastRun(bool successful=true)
virtual void SetLastRun(const QDateTime &last, bool successful=true)
HouseKeeperTask(const QString &dbTag, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
virtual bool DoCheckRun(const QDateTime &)
HouseKeeperStartup m_startup
QDateTime GetLastSuccess(void)
bool ConfirmRun(void) const
void customEvent(QEvent *e) override
QMap< QString, HouseKeeperTask * > m_taskMap
void StartThread(void)
Wake the primary run thread, or create a new one.
QQueue< HouseKeeperTask * > m_taskQueue
QList< HouseKeepingThread * > m_threadList
HouseKeeperTask * GetQueuedTask(void)
void RegisterTask(HouseKeeperTask *task)
Thread used to perform queued HouseKeeper tasks.
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
QWaitCondition m_waitCondition
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
int numRowsAffected() const
bool isConnected(void) const
Only updated once during object creation.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
QString GetHostName(void)
void SendEvent(const MythEvent &event)
static void DBError(const QString &where, const MSqlQuery &query)
This class is used as a container for messages.
const QString & Message() const
static const Type kMythEventMessage
void addListener(QObject *listener)
Add a listener to the observable.
void removeListener(QObject *listener)
Remove a listener to the observable.
Modified HouseKeeperTask for tasks to be run at a regular interval.
bool DoCheckRun(const QDateTime &now) override
virtual void CalculateWindow(void)
PeriodicHouseKeeperTask(const QString &dbTag, std::chrono::seconds period, float min=0.5, float max=1.1, std::chrono::seconds retry=0s, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
QPair< float, float > m_windowPercent
void SetLastRun(const QDateTime &last, bool successful=true) override
virtual bool PastWindow(const QDateTime &now)
std::chrono::seconds m_retry
QDateTime UpdateLastRun(const QDateTime &last, bool successful=true) override
virtual bool InWindow(const QDateTime &now)
virtual void SetWindow(float min, float max)
std::chrono::seconds m_period
QPair< std::chrono::seconds, std::chrono::seconds > m_windowElapsed
General purpose reference counter.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
This decrements the reference on destruction.
@ kHKGlobal
task should only run once per cluster e.g.
@ kHKInst
task should run on every process e.g.
@ kHKLocal
task should only run once per machine e.g.
@ kHKRunImmediateOnStartup
task is run during HouseKeeper startup
@ kHKRunOnStartup
task is queued when HouseKeeper is started
static constexpr T chronomult(T duration, double f)
Multiply a duration by a float, returning a duration.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(int64_t seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.