55#include <QMutexLocker>
123 LOG(VB_GENERAL, LOG_DEBUG, QString(
"%1 Running? %2/In window? %3.")
146 LOG(VB_GENERAL, LOG_INFO, QString(
"Running HouseKeeperTask '%1'.")
151 LOG(VB_GENERAL, LOG_WARNING, QString(
"HouseKeeperTask '%1' already "
152 "running. Refusing to run concurrently").arg(
m_dbTag));
161 LOG(VB_GENERAL, LOG_INFO, QString(
"HouseKeeperTask '%1' Failed.")
166 LOG(VB_GENERAL, LOG_INFO,
167 QString(
"HouseKeeperTask '%1' Finished Successfully.")
200 query.
prepare(
"SELECT lastrun,lastsuccess FROM housekeeping"
202 " AND hostname IS NULL");
206 query.
prepare(
"SELECT lastrun,lastsuccess FROM housekeeping"
208 " AND hostname = :HOST");
239 query.
prepare(
"UPDATE `housekeeping` SET `lastrun`=:TIME,"
240 " `lastsuccess`=:STIME"
241 " WHERE `tag` = :TAG"
242 " AND `hostname` IS NULL");
246 query.
prepare(
"UPDATE `housekeeping` SET `lastrun`=:TIME,"
247 " `lastsuccess`=:STIME"
248 " WHERE `tag` = :TAG"
249 " AND `hostname` = :HOST");
264 LOG(VB_GENERAL, LOG_DEBUG, QString(
"%1: UPDATEd %2 run time.")
272 query.
prepare(
"INSERT INTO `housekeeping`"
273 " (`tag`, `lastrun`, `lastsuccess`)"
274 " VALUES (:TAG, :TIME, :STIME)");
278 query.
prepare(
"INSERT INTO `housekeeping`"
279 " (`tag`, `hostname`, `lastrun`, `lastsuccess`)"
280 " VALUES (:TAG, :HOST, :TIME, :STIME)");
292 LOG(VB_GENERAL, LOG_DEBUG, QString(
"%1: INSERTed %2 run time.")
299 msg = QString(
"HOUSE_KEEPER_SUCCESSFUL %1 %2 %3");
301 msg = QString(
"HOUSE_KEEPER_RUNNING %1 %2 %3");
334 std::chrono::seconds period,
float min,
float max, std::chrono::seconds retry,
337 m_windowPercent(min, max)
346 std::chrono::seconds period =
m_period;
383 auto elapsed = std::chrono::seconds(
GetLastRun().secsTo(now));
398 double prob = 1.0 - (duration_cast<floatsecs>(elapsed -
m_windowElapsed.first) /
412 bool res = (
MythRandom() > (uint32_t)(prob2 * std::numeric_limits<uint32_t>::max()));
425 auto elapsed = std::chrono::seconds(
GetLastRun().secsTo(now));
456 m_windowHour(0h, 23h)
462 std::chrono::hours minhour, std::chrono::hours maxhour,
465 m_windowHour(minhour, maxhour)
475 QDateTime tmp = QDateTime(date, QTime(
m_windowHour.first.count(), 0));
479 tmp = QDateTime(date, QTime(
m_windowHour.second.count(), 30));
485 LOG(VB_GENERAL, LOG_DEBUG, QString(
"%1 Run window between %2 - %3.")
502 auto hour = std::chrono::hours(now.time().hour());
581 : m_timer(new QTimer(this))
611 for (
auto *it : std::as_const(
m_taskMap))
633 QMap<QString,HouseKeeperTask*>::iterator it =
m_taskMap.begin();
645 QString tag = task->
GetTag();
649 LOG(VB_GENERAL, LOG_ERR,
650 QString(
"HouseKeeperTask '%1' already registered. "
651 "Rejecting duplicate.").arg(tag));
655 LOG(VB_GENERAL, LOG_INFO,
656 QString(
"Registering HouseKeeperTask '%1'.").arg(tag));
667 LOG(VB_GENERAL, LOG_ERR,
668 QString(
"HouseKeeperTask '%1' doesn't exist.").arg(tag));
673 LOG(VB_GENERAL, LOG_INFO,
674 QString(
"HouseKeeperTask '%1' destroyed.").arg(tag));
702 query.
prepare(
"SELECT `tag`,`lastrun`"
703 " FROM `housekeeping`"
704 " WHERE `hostname` = :HOST"
705 " OR `hostname` IS NULL");
717 QString tag = query.
value(0).toString();
729 if ((*it)->CheckImmediate())
732 (*it)->UpdateLastRun();
735 else if ((*it)->CheckStartup())
738 LOG(VB_GENERAL, LOG_INFO,
739 QString(
"Queueing HouseKeeperTask '%1'.").arg(it.key()));
746 LOG(VB_GENERAL, LOG_INFO,
"Starting HouseKeeper.");
753 LOG(VB_GENERAL, LOG_DEBUG,
"Running HouseKeeper.");
761 if ((*it)->IsFinished())
763 LOG(VB_GENERAL, LOG_INFO,
764 QString(
"Removing finished HouseKeeperTask '%1'.")
777 if ((*it)->CheckRun(now))
779 LOG(VB_GENERAL, LOG_INFO,
780 QString(
"Queueing HouseKeeperTask '%1'.").arg(it.key()));
801 if ((*it)->isRunning())
815 LOG(VB_GENERAL, LOG_DEBUG,
816 QString(
"Discarded HouseKeepingThreads have completed and "
817 "been deleted. Current count %1 -> %2.")
818 .arg(count1).arg(count2));
844 LOG(VB_GENERAL, LOG_DEBUG,
"Running initial HouseKeepingThread.");
855 LOG(VB_GENERAL, LOG_DEBUG,
856 QString(
"Current HouseKeepingThread is delayed on task, "
857 "spawning replacement. Current count %1.")
868 LOG(VB_GENERAL, LOG_DEBUG,
"Waking HouseKeepingThread.");
880 if ((me->Message().left(20) ==
"HOUSE_KEEPER_RUNNING") ||
881 (me->Message().left(23) ==
"HOUSE_KEEPER_SUCCESSFUL"))
883 QStringList tokens = me->
Message()
884 .split(
" ", Qt::SkipEmptyParts);
885 if (tokens.size() != 4)
888 const QString&
hostname = tokens[1];
889 const QString& tag = tokens[2];
891 bool successful = me->Message().contains(
"SUCCESSFUL");
903 m_taskMap[tag]->SetLastRun(last, successful);
912 GetMythDB()->GetDBManager()->PurgeIdleConnections(
false);
bool DoRun(void) override
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 UnregisterTask(const QString &tag)
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_)
Convenience inline random number generator functions.
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.
uint32_t MythRandom()
generate 32 random bits