Restarts: History
A Detector keeps its state in memory. After a restart, a Rule like after(maintenance) has forgotten the last maintenance. Pass the Events stored before the restart to the new Detector as History, and Rules that refer to earlier Events (after, unless, count, totalDuration, latest(...).duration()) carry on across the restart. History restores no Channel values, moving averages or running Events: an Event running at the restart is Ended Truncated by close(), and the new Detector starts a new one with a Truncated start.
Storing Events and handing them back
Before the restart, store the Ended Events, for example in onEnded. After it, load them and give them to the builder with history(...):
// before the restart: store Ended Events, e.g. in onEnded
List<Event> stored = loadFromDatabase();
Rule maintenance = Rule.named("Maintenance").when(serviceMode.above(0.5));
Rule overdueService = Rule.named("OverdueService")
.when(after(maintenance).within(Duration.ofDays(90)).not());
Detector detector = Detector.builder()
.rules(maintenance, overdueService)
.history(stored)
.build();
A service that is due every 90 days
A machine reports whether it is in service mode once a day, for 200 days; it is serviced on days 10 and 140. OverdueService holds while there was no Maintenance in the last 90 days. At the restart, the Detector is closed and a new one takes over from that day.
The live chart and its controls need JavaScript. The tables show the Events at the default parameters.
The site cannot run the default parameters: (JavaScript) TypeError: Cannot read properties of undefined (reading 'length')
import static io.github.romanhaendler.rbed.Conditions.*;
import io.github.romanhaendler.rbed.*;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Channel serviceMode = Channel.named("serviceMode");
Rule maintenance = Rule.named("Maintenance").when(serviceMode.above(0.5));
Rule overdueService = Rule.named("OverdueService")
.when(after(maintenance).within(Duration.ofDays(90)).not());
long day = Duration.ofDays(1).toMillis();
// before the restart: store the Ended Events (in a database; here in a list)
List<Event> stored = new ArrayList<>();
Detector before = Detector.builder()
.rules(maintenance, overdueService)
.listener(new EventListener() {
@Override public void onEnded(Event e) { stored.add(e); }
})
.build();
for (int d = 0; d < 60; d++) { // one Sample a day, maintenance on days 10 and 140
before.push(d * day, Map.of(serviceMode, d == 10 || d == 140 ? 1.0 : 0.0));
}
before.close();
// after the restart
Detector restarted = Detector.builder()
.rules(maintenance, overdueService)
.history(stored)
.build();
for (int d = 60; d <= 200; d++) {
restarted.push(d * day, Map.of(serviceMode, d == 10 || d == 140 ? 1.0 : 0.0));
}
restarted.close();
At the defaults, with History, the restarted Detector knows the maintenance of day 10, so the service is overdue from day 102, when that maintenance lies more than 90 days back, until the next one is over on day 141. Choose "Without History", and the new Detector knows of no maintenance at all: from the restart on day 60 the service counts as overdue, at once and with a Truncated start.
The Detector before the restart is in the same position at day 0: it has no History, so the service counts as overdue until the first maintenance it sees.
Things to try
- Move the restart to day 120, more than 90 days after the maintenance of day 10: History makes no difference. The service is overdue either way, split at the restart into two Truncated Events: one Ended by
close()at day 119, and one that starts with the new Detector at day 120.
What History is used for
History Events are matched to Rules by name(), so each must belong to a Rule added to the Detector. They must be Confirmed and Ended (both confirmed() and end() present), and the first Sample must come after the latest of their ends. after, unless, count, totalDuration and latest(...).duration() take them into account. They carry no Aggregates for latest(...).min/max/mean, and they are not reported to the listener again.
Reference
- Restarts: History in the README, the canonical text
- Detector.Builder in the Javadoc:
history
Methods used: Channel.named, Rule.named, Rule.when, Expression.above, Conditions.after, After.within, Condition.not, Detector.builder, Detector.Builder.rules, Detector.Builder.listener, EventListener.onEnded, Detector.Builder.build, Detector.push, Detector.close, Detector.Builder.history.