mirror of
https://github.com/PerMalmberg/libcron.git
synced 2025-04-22 08:23:04 -05:00
Handles jumps backwards backwards >3h
This commit is contained in:
parent
97a0a5a9c2
commit
35a35d99e9
1
.gitignore
vendored
1
.gitignore
vendored
@ -33,3 +33,4 @@
|
|||||||
|
|
||||||
cmake-build-*
|
cmake-build-*
|
||||||
.idea/workspace.xml
|
.idea/workspace.xml
|
||||||
|
out/*
|
@ -122,12 +122,12 @@ namespace libcron
|
|||||||
t.calculate_next(now);
|
t.calculate_next(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(now < last_tick && now - last_tick < hours{3})
|
else if (now < last_tick && now - last_tick <= -hours{3})
|
||||||
{
|
{
|
||||||
// Prevent tasks from running until the clock has reached current 'last_tick'.
|
// Reschedule all tasks.
|
||||||
for (auto& t : tasks.get_tasks())
|
for (auto& t : tasks.get_tasks())
|
||||||
{
|
{
|
||||||
//t.set_back_limit(last_tick);
|
t.calculate_next(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ namespace libcron
|
|||||||
executed.push_back(tasks.top());
|
executed.push_back(tasks.top());
|
||||||
tasks.pop();
|
tasks.pop();
|
||||||
auto& t = executed[executed.size() - 1];
|
auto& t = executed[executed.size() - 1];
|
||||||
t.execute();
|
t.execute(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = executed.size();
|
res = executed.size();
|
||||||
|
@ -15,6 +15,9 @@ namespace libcron
|
|||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
next_schedule = std::get<1>(result);
|
next_schedule = std::get<1>(result);
|
||||||
|
|
||||||
|
// Make sure that the task is allowed to run.
|
||||||
|
last_run = next_schedule - 1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
@ -22,7 +25,7 @@ namespace libcron
|
|||||||
|
|
||||||
bool Task::is_expired(std::chrono::system_clock::time_point now) const
|
bool Task::is_expired(std::chrono::system_clock::time_point now) const
|
||||||
{
|
{
|
||||||
return valid && time_until_expiry(now) == 0s;
|
return valid && now >= last_run && time_until_expiry(now) == 0s;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::system_clock::duration Task::time_until_expiry(std::chrono::system_clock::time_point now) const
|
std::chrono::system_clock::duration Task::time_until_expiry(std::chrono::system_clock::time_point now) const
|
||||||
|
@ -17,8 +17,9 @@ namespace libcron
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute() const
|
void execute(std::chrono::system_clock::time_point now)
|
||||||
{
|
{
|
||||||
|
last_run = now;
|
||||||
task();
|
task();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,5 +52,6 @@ namespace libcron
|
|||||||
std::chrono::system_clock::time_point next_schedule;
|
std::chrono::system_clock::time_point next_schedule;
|
||||||
std::function<void()> task;
|
std::function<void()> task;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
std::chrono::system_clock::time_point last_run = std::numeric_limits<std::chrono::system_clock::time_point>::min();
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -19,177 +19,177 @@ std::string create_schedule_expiring_in(std::chrono::system_clock::time_point no
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SCENARIO("Adding a task")
|
SCENARIO("Adding a task")
|
||||||
//{
|
{
|
||||||
// GIVEN("A Cron instance with no task")
|
GIVEN("A Cron instance with no task")
|
||||||
// {
|
{
|
||||||
// Cron<> c;
|
Cron<> c;
|
||||||
// auto expired = false;
|
auto expired = false;
|
||||||
//
|
|
||||||
// THEN("Starts with no task")
|
THEN("Starts with no task")
|
||||||
// {
|
{
|
||||||
// REQUIRE(c.count() == 0);
|
REQUIRE(c.count() == 0);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// WHEN("Adding a task that runs every second")
|
WHEN("Adding a task that runs every second")
|
||||||
// {
|
{
|
||||||
// REQUIRE(c.add_schedule("A task", "* * * * * ?",
|
REQUIRE(c.add_schedule("A task", "* * * * * ?",
|
||||||
// [&expired]()
|
[&expired]()
|
||||||
// {
|
{
|
||||||
// expired = true;
|
expired = true;
|
||||||
// })
|
})
|
||||||
// );
|
);
|
||||||
//
|
|
||||||
// THEN("Count is 1 and task was not expired two seconds ago")
|
THEN("Count is 1 and task was not expired two seconds ago")
|
||||||
// {
|
{
|
||||||
// REQUIRE(c.count() == 1);
|
REQUIRE(c.count() == 1);
|
||||||
// c.tick(c.get_clock().now() - 2s);
|
c.tick(c.get_clock().now() - 2s);
|
||||||
// REQUIRE_FALSE(expired);
|
REQUIRE_FALSE(expired);
|
||||||
// }
|
}
|
||||||
// AND_THEN("Task is expired when calculating based on current time")
|
AND_THEN("Task is expired when calculating based on current time")
|
||||||
// {
|
{
|
||||||
// c.tick();
|
c.tick();
|
||||||
// THEN("Task is expired")
|
THEN("Task is expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE(expired);
|
REQUIRE(expired);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//SCENARIO("Adding a task that expires in the future")
|
SCENARIO("Adding a task that expires in the future")
|
||||||
//{
|
{
|
||||||
// GIVEN("A Cron instance with task expiring in 3 seconds")
|
GIVEN("A Cron instance with task expiring in 3 seconds")
|
||||||
// {
|
{
|
||||||
// auto expired = false;
|
auto expired = false;
|
||||||
//
|
|
||||||
// Cron<> c;
|
Cron<> c;
|
||||||
// REQUIRE(c.add_schedule("A task",
|
REQUIRE(c.add_schedule("A task",
|
||||||
// create_schedule_expiring_in(c.get_clock().now(), hours{0}, minutes{0}, seconds{3}),
|
create_schedule_expiring_in(c.get_clock().now(), hours{0}, minutes{0}, seconds{3}),
|
||||||
// [&expired]()
|
[&expired]()
|
||||||
// {
|
{
|
||||||
// expired = true;
|
expired = true;
|
||||||
// })
|
})
|
||||||
// );
|
);
|
||||||
//
|
|
||||||
// THEN("Not yet expired")
|
THEN("Not yet expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE_FALSE(expired);
|
REQUIRE_FALSE(expired);
|
||||||
// }
|
}
|
||||||
// AND_WHEN("When waiting one second")
|
AND_WHEN("When waiting one second")
|
||||||
// {
|
{
|
||||||
// std::this_thread::sleep_for(1s);
|
std::this_thread::sleep_for(1s);
|
||||||
// c.tick();
|
c.tick();
|
||||||
// THEN("Task has not yet expired")
|
THEN("Task has not yet expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE_FALSE(expired);
|
REQUIRE_FALSE(expired);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// AND_WHEN("When waiting three seconds")
|
AND_WHEN("When waiting three seconds")
|
||||||
// {
|
{
|
||||||
// std::this_thread::sleep_for(3s);
|
std::this_thread::sleep_for(3s);
|
||||||
// c.tick();
|
c.tick();
|
||||||
// THEN("Task has expired")
|
THEN("Task has expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE(expired);
|
REQUIRE(expired);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//SCENARIO("Task priority")
|
SCENARIO("Task priority")
|
||||||
//{
|
{
|
||||||
// GIVEN("A Cron instance with two tasks expiring in 3 and 5 seconds, added in 'reverse' order")
|
GIVEN("A Cron instance with two tasks expiring in 3 and 5 seconds, added in 'reverse' order")
|
||||||
// {
|
{
|
||||||
// auto _3_second_expired = 0;
|
auto _3_second_expired = 0;
|
||||||
// auto _5_second_expired = 0;
|
auto _5_second_expired = 0;
|
||||||
//
|
|
||||||
//
|
|
||||||
// Cron<> c;
|
Cron<> c;
|
||||||
// REQUIRE(c.add_schedule("Five",
|
REQUIRE(c.add_schedule("Five",
|
||||||
// create_schedule_expiring_in(c.get_clock().now(), hours{0}, minutes{0}, seconds{5}),
|
create_schedule_expiring_in(c.get_clock().now(), hours{0}, minutes{0}, seconds{5}),
|
||||||
// [&_5_second_expired]()
|
[&_5_second_expired]()
|
||||||
// {
|
{
|
||||||
// _5_second_expired++;
|
_5_second_expired++;
|
||||||
// })
|
})
|
||||||
// );
|
);
|
||||||
//
|
|
||||||
// REQUIRE(c.add_schedule("Three",
|
REQUIRE(c.add_schedule("Three",
|
||||||
// create_schedule_expiring_in(c.get_clock().now(), hours{0}, minutes{0}, seconds{3}),
|
create_schedule_expiring_in(c.get_clock().now(), hours{0}, minutes{0}, seconds{3}),
|
||||||
// [&_3_second_expired]()
|
[&_3_second_expired]()
|
||||||
// {
|
{
|
||||||
// _3_second_expired++;
|
_3_second_expired++;
|
||||||
// })
|
})
|
||||||
// );
|
);
|
||||||
//
|
|
||||||
// THEN("Not yet expired")
|
THEN("Not yet expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE_FALSE(_3_second_expired);
|
REQUIRE_FALSE(_3_second_expired);
|
||||||
// REQUIRE_FALSE(_5_second_expired);
|
REQUIRE_FALSE(_5_second_expired);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// WHEN("Waiting 1 seconds")
|
WHEN("Waiting 1 seconds")
|
||||||
// {
|
{
|
||||||
// std::this_thread::sleep_for(1s);
|
std::this_thread::sleep_for(1s);
|
||||||
// c.tick();
|
c.tick();
|
||||||
//
|
|
||||||
// THEN("Task has not yet expired")
|
THEN("Task has not yet expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE(_3_second_expired == 0);
|
REQUIRE(_3_second_expired == 0);
|
||||||
// REQUIRE(_5_second_expired == 0);
|
REQUIRE(_5_second_expired == 0);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// AND_WHEN("Waiting 3 seconds")
|
AND_WHEN("Waiting 3 seconds")
|
||||||
// {
|
{
|
||||||
// std::this_thread::sleep_for(3s);
|
std::this_thread::sleep_for(3s);
|
||||||
// c.tick();
|
c.tick();
|
||||||
//
|
|
||||||
// THEN("3 second task has expired")
|
THEN("3 second task has expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE(_3_second_expired == 1);
|
REQUIRE(_3_second_expired == 1);
|
||||||
// REQUIRE(_5_second_expired == 0);
|
REQUIRE(_5_second_expired == 0);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// AND_WHEN("Waiting 5 seconds")
|
AND_WHEN("Waiting 5 seconds")
|
||||||
// {
|
{
|
||||||
// std::this_thread::sleep_for(5s);
|
std::this_thread::sleep_for(5s);
|
||||||
// c.tick();
|
c.tick();
|
||||||
//
|
|
||||||
// THEN("3 and 5 second task has expired")
|
THEN("3 and 5 second task has expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE(_3_second_expired == 1);
|
REQUIRE(_3_second_expired == 1);
|
||||||
// REQUIRE(_5_second_expired == 1);
|
REQUIRE(_5_second_expired == 1);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// AND_WHEN("Waiting based on the time given by the Cron instance")
|
AND_WHEN("Waiting based on the time given by the Cron instance")
|
||||||
// {
|
{
|
||||||
// std::this_thread::sleep_for(c.time_until_next());
|
std::this_thread::sleep_for(c.time_until_next());
|
||||||
// c.tick();
|
c.tick();
|
||||||
//
|
|
||||||
// THEN("3 second task has expired")
|
THEN("3 second task has expired")
|
||||||
// {
|
{
|
||||||
// REQUIRE(_3_second_expired == 1);
|
REQUIRE(_3_second_expired == 1);
|
||||||
// REQUIRE(_5_second_expired == 0);
|
REQUIRE(_5_second_expired == 0);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// AND_WHEN("Waiting based on the time given by the Cron instance")
|
AND_WHEN("Waiting based on the time given by the Cron instance")
|
||||||
// {
|
{
|
||||||
// std::this_thread::sleep_for(c.time_until_next());
|
std::this_thread::sleep_for(c.time_until_next());
|
||||||
// REQUIRE(c.tick() == 1);
|
REQUIRE(c.tick() == 1);
|
||||||
//
|
|
||||||
// std::this_thread::sleep_for(c.time_until_next());
|
std::this_thread::sleep_for(c.time_until_next());
|
||||||
// REQUIRE(c.tick() == 1);
|
REQUIRE(c.tick() == 1);
|
||||||
//
|
|
||||||
// THEN("3 and 5 second task has each expired once")
|
THEN("3 and 5 second task has each expired once")
|
||||||
// {
|
{
|
||||||
// REQUIRE(_3_second_expired == 1);
|
REQUIRE(_3_second_expired == 1);
|
||||||
// REQUIRE(_5_second_expired == 1);
|
REQUIRE(_5_second_expired == 1);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
class TestClock
|
class TestClock
|
||||||
: public ICronClock
|
: public ICronClock
|
||||||
{
|
{
|
||||||
@ -261,16 +261,33 @@ SCENARIO("Clock changes")
|
|||||||
THEN("Task are rescheduled, not run")
|
THEN("Task are rescheduled, not run")
|
||||||
{
|
{
|
||||||
REQUIRE(c.tick() == 1);
|
REQUIRE(c.tick() == 1);
|
||||||
std::cout << "0: " << c << std::endl;
|
|
||||||
clock.add(hours{3}); // 03:00
|
clock.add(hours{3}); // 03:00
|
||||||
REQUIRE(c.tick() == 1); // Rescheduled
|
REQUIRE(c.tick() == 1); // Rescheduled
|
||||||
std::cout << "1: " << c << std::endl;
|
|
||||||
clock.add(minutes{15}); // 03:15
|
clock.add(minutes{15}); // 03:15
|
||||||
REQUIRE(c.tick() == 0);
|
REQUIRE(c.tick() == 0);
|
||||||
std::cout << "2: " << c << std::endl;
|
|
||||||
clock.add(minutes{45}); // 04:00
|
clock.add(minutes{45}); // 04:00
|
||||||
REQUIRE(c.tick() == 1);
|
REQUIRE(c.tick() == 1);
|
||||||
std::cout << "3: " << c << std::endl;
|
}
|
||||||
|
}
|
||||||
|
AND_WHEN("Clock is moved back <3h")
|
||||||
|
{
|
||||||
|
THEN("Tasks retain their last scheduled time and are prevented from running twice")
|
||||||
|
{
|
||||||
|
REQUIRE(c.tick() == 1);
|
||||||
|
clock.add(-hours{1}); // 23:00
|
||||||
|
REQUIRE(c.tick() == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AND_WHEN("Clock is moved back >3h")
|
||||||
|
{
|
||||||
|
THEN("Tasks are rescheduled")
|
||||||
|
{
|
||||||
|
REQUIRE(c.tick() == 1);
|
||||||
|
clock.add(-hours{3}); // 23:00
|
||||||
|
REQUIRE(c.tick() == 1);
|
||||||
|
REQUIRE(c.tick() == 0);
|
||||||
|
clock.add(hours{1}); // 00:00
|
||||||
|
REQUIRE(c.tick() == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user