# 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(...)`:

```java
// 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.

Parameters (in the page address as ?restart=…):

- Restart on day (`restart`): 20 to 180 d in steps of 10, default 60
- After the restart (`history`): 0 for With History (default), 1 for Without History

The site cannot run the default parameters: (JavaScript) TypeError: Cannot read properties of undefined (reading 'length')

Java source at the default parameters:

```java
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](https://github.com/romanhaendler/rbed#restarts-history) in the README, the canonical text
- [Detector.Builder](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.Builder.html) in the Javadoc: `history`

Methods used: [`Channel.named`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Channel.html#named%28java.lang.String%29), [`Rule.named`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Rule.html#named%28java.lang.String%29), [`Rule.when`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Rule.html#when%28io.github.romanhaendler.rbed.Condition%29), [`Expression.above`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Expression.html#above%28double%29), [`Conditions.after`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Conditions.html#after%28io.github.romanhaendler.rbed.Rule%29), [`After.within`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/After.html#within%28java.time.Duration%29), [`Condition.not`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Condition.html#not%28%29), [`Detector.builder`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.html#builder%28%29), [`Detector.Builder.rules`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.Builder.html#rules%28io.github.romanhaendler.rbed.Rule...%29), [`Detector.Builder.listener`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.Builder.html#listener%28io.github.romanhaendler.rbed.EventListener%29), [`EventListener.onEnded`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/EventListener.html#onEnded%28io.github.romanhaendler.rbed.Event%29), [`Detector.Builder.build`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.Builder.html#build%28%29), [`Detector.push`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.html#push%28long,java.util.Map%29), [`Detector.close`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.html#close%28%29), [`Detector.Builder.history`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.Builder.html#history%28java.util.Collection%29).
