diff --git a/kubernetes/seed/influxdb/seed-job.yaml b/kubernetes/seed/influxdb/seed-job.yaml index 0bc0dcaa..25689498 100644 --- a/kubernetes/seed/influxdb/seed-job.yaml +++ b/kubernetes/seed/influxdb/seed-job.yaml @@ -124,30 +124,49 @@ spec: # `pipefail` (bash-only, hence the `command: bash` above): # an `influx query` EOF inside the pipe propagates a non- # zero exit, the loop aborts, the Job retries. + # Resume from the last completed day if a sentinel exists in + # the staging PVC. Without this, kubelet's OnFailure restart + # would replay from 2018 every time — 30+ min of retraced + # empty days per retry — and the same bad chunk would burn + # the backoffLimit before reaching new ground. + SENTINEL=/staging/last-completed-day START="2018-01-01T00:00:00Z" - # Stop at tomorrow → covers today inclusively. END=$(date -u -d "tomorrow" +%Y-%m-%dT00:00:00Z) - CUR="$START" + if [[ -f "$SENTINEL" ]]; then + CUR=$(cat "$SENTINEL") + log "Resuming from $CUR (sentinel)" + else + CUR="$START" + log "Starting fresh from $CUR" + fi + while [[ "$CUR" < "$END" ]]; do NEXT=$(date -u -d "$CUR +1 day" +%Y-%m-%dT00:00:00Z) log "Streaming $CUR → $NEXT ..." - # Filter out the `_field == "source"` rows: HA writes - # `source` as both a tag (which integration emitted the - # point) AND a field (some entity attributes) on the - # same measurement. pivot() cannot materialise a field- - # derived column whose name collides with an existing - # tag column, so it errors out at the first row that - # has _field=source. Dropping that one field keeps the - # `source` tag intact (the more useful of the two) at - # the cost of losing the entity-attribute field, which - # is rarely populated and unique per entity. + # Filters in front of pivot, ordered by issue: + # + # 1. `_field == "source"`: HA writes `source` as both a + # tag (integration emitter, e.g. "Home Assistant") AND + # a field (some entity attributes). pivot() can't + # materialise a field-derived column with the same + # name as an existing tag column. Drop the field, keep + # the tag (more useful — drives Grafana datasource + # filters). + # + # 2. `domain == "update"`: HA's update domain entities + # carry markdown release notes in `release_summary_str` + # with embedded newlines. `influx write --format csv` + # can't parse multi-line quoted strings and rejects + # the entire line. Update entries are state-toggle + # metadata (update available y/n + version strings), + # not useful time-series — safe to drop wholesale. influx query --raw \ --host "$LEGACY_HOST" \ --token "$LEGACY_TOKEN" \ --org "$LEGACY_ORG" \ "from(bucket: \"$LEGACY_BUCKET\") |> range(start: $CUR, stop: $NEXT) - |> filter(fn: (r) => r._field != \"source\") + |> filter(fn: (r) => r._field != \"source\" and r.domain != \"update\") |> pivot(rowKey: [\"_time\"], columnKey: [\"_field\"], valueColumn: \"_value\") |> drop(columns: [\"_start\", \"_stop\"])" \ | influx write \ @@ -156,6 +175,9 @@ spec: --org "$INFLUX_ORG" \ --bucket "$INFLUX_BUCKET" \ --format csv + # Day complete — checkpoint so a kubelet OnFailure restart + # picks up here instead of replaying from 2018. + echo "$NEXT" > "$SENTINEL" CUR="$NEXT" done