milestone 20: declarative configuration for iac
This commit is contained in:
@@ -1199,6 +1199,14 @@ pub const Manager = struct {
|
||||
|
||||
if (state != .ok) return true;
|
||||
const last = row.last_updated orelse return true;
|
||||
// The Pi has no RTC, so a fetch stamped while the clock ran ahead of
|
||||
// real time (a pre-NTP boot, a restored image) leaves a `last_updated`
|
||||
// in the future. Plain interval arithmetic would then suspend every
|
||||
// refresh until real time caught up with the poison stamp, and the
|
||||
// reconcile engine preserves runtime columns faithfully, so nothing
|
||||
// else would ever clear it. A stamp from the future is not evidence of
|
||||
// a recent fetch.
|
||||
if (last > now) return true;
|
||||
return now - last >= model.updateIntervalSeconds(self.update);
|
||||
}
|
||||
|
||||
@@ -1674,6 +1682,40 @@ test "acquire before any reload returns null and holds no lock" {
|
||||
manager.lock.unlock(io);
|
||||
}
|
||||
|
||||
test "needsRefresh treats a last_updated in the future as due" {
|
||||
var threaded: std.Io.Threaded = .init(testing.allocator, .{});
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
var database = try openMigrated();
|
||||
defer database.close();
|
||||
|
||||
var f: fetcher.Fetcher = undefined;
|
||||
var manager = try testManager(&database, &f);
|
||||
defer manager.deinit(io);
|
||||
|
||||
// `.ok` is the only state that consults the clock at all; every other one
|
||||
// is already due, so the arithmetic below would be unreachable without it.
|
||||
var statuses = [_]SourceStatus{.{ .id = 1, .state = .ok }};
|
||||
manager.statuses = &statuses;
|
||||
defer manager.statuses = &.{};
|
||||
|
||||
const row = testRow(1, true);
|
||||
const stamp = row.last_updated.?;
|
||||
const interval = model.updateIntervalSeconds(manager.update);
|
||||
|
||||
// The ordinary cases still hold: fresh is not due, stale is.
|
||||
try testing.expect(!manager.needsRefresh(io, row, stamp + 1));
|
||||
try testing.expect(manager.needsRefresh(io, row, stamp + interval));
|
||||
|
||||
// The Pi has no RTC. A fetch stamped while the clock ran ahead of real
|
||||
// time leaves `now - last` negative, which reads as "fetched moments ago"
|
||||
// and suspends every refresh until real time catches the poison stamp —
|
||||
// for a whole day here, and for as long as the clock was wrong in general.
|
||||
try testing.expect(manager.needsRefresh(io, row, stamp - 1));
|
||||
try testing.expect(manager.needsRefresh(io, row, stamp - 86_400));
|
||||
}
|
||||
|
||||
test "the disk gate skips a scheduled refresh only while writes are critical" {
|
||||
var threaded: std.Io.Threaded = .init(testing.allocator, .{});
|
||||
defer threaded.deinit();
|
||||
|
||||
Reference in New Issue
Block a user