Warning, /swf-monitor/docs/SNAPPER_CATALOG.md is written in an unsupported language. File is not indexed.
0001 # Snapper Catalog — the JLab Rucio catalog component and view
0002
0003 The behavior of the JLab Rucio catalog, the catalog of record every
0004 production job registers its outputs in, becomes part of the recorded
0005 system history: a `catalog` component captured in Snapper snaps, and a
0006 Catalog view showing what the jobs asked of the catalog, what they got,
0007 and how the catalog was answering, on one time axis. It follows the
0008 platform component's shape ([SNAPPER_PLATFORM.md](SNAPPER_PLATFORM.md):
0009 a maintainer on the five-minute refresh, measured gauges beside
0010 assessed interval readings) and the errors component's evidence idiom
0011 ([SNAPPER_ERRORS.md](SNAPPER_ERRORS.md): an interval's events as rows
0012 that any window sums), on the mechanism of [SNAPPER.md](SNAPPER.md).
0013
0014 The component, the view and the backfill are in production since
0015 2026-09-16 (the latency and registrar groups in their first form; the
0016 queue selector, the alarm and the registrar's completions follow).
0017 Design of record, written 2026-09-16 on the day the catalog collapsed
0018 under three 50,000-job tasks: the Rucio server's WSGI daemon saturated
0019 (JLab: "listener backlog limit exceeded"), registrations went from
0020 none failing at 09:30 ET to 77% failing by 12:30, and 8,000 finished
0021 jobs were lost before the tasks were paused. Nothing recorded showed
0022 it as it happened; the Storage view's arrivals would have shown it
0023 sagging, hours later.
0024
0025 ## Historical questions
0026
0027 - At an instant, was the catalog answering, and how fast, from the
0028 platform's side and from the jobs' side?
0029 - How many registrations were attempted in the interval, and what
0030 became of them: registered, pending (the catalog unreachable, the
0031 registrar owes it), stashed at BNL, or lost with the job?
0032 - When the catalog degraded, which came first, the load or the
0033 latency, and by how much lead?
0034 - What did the registrar owe, and was it draining?
0035
0036 ## The catalog component
0037
0038 Internal name `catalog`, epicprod scope, published by a maintainer
0039 module (`monitor_app/snapper_catalog.py`) beside the platform and
0040 error-state maintainers on the same five-minute System-status refresh.
0041 Publisher identity `swf-monitor:jlab-catalog`, assessment policy
0042 `swf-jlab-catalog-v1`, schema version 1. Four groups, each with its kind:
0043
0044 **Probe (gauges, measured by the maintainer).** From the swf-monitor
0045 host, timed: a TLS handshake with the Rucio server (`rucio.cfg`'s
0046 `auth_host`), the server's `/ping`, and one authenticated light read
0047 through the production account (the metadata of a fixed dataset), each
0048 as milliseconds with a timeout recorded as a timeout, never omitted.
0049 Question: was the catalog answering, from outside the job wave.
0050
0051 **Registrations (interval assessment, from the job record).** Over
0052 the half-open interval since the previous publication, every
0053 production job that ended, read from the PanDA record's job-metrics
0054 digest, which every job carries whatever its end
0055 (`payloadRegistration`, `payloadExit`, `payloadVersion`,
0056 EPICPROD_PAYLOAD.md § Reporting from a job that fails): counts of
0057 jobs whose registration was `ok`, `pending`, `stashed`, `failed`
0058 (the job ended with the registration lost), and `not_reached`;
0059 of the failed, the split by payload exit code (1, 78, 81); per
0060 queue in a bounded map. Question: what the jobs asked, and what they
0061 got.
0062
0063 **Latency (interval assessment, from the payload reports).** The
0064 registration stage's wall seconds over the jobs of the interval whose
0065 report has been ingested (`swf_epicprod_jobs`, the report sweep and
0066 the outputs ingest): count, median and 90th percentile, and the same
0067 for the jobs whose registration succeeded alone. The report lags the
0068 job by the ingest cadence, so this reading trails the registrations
0069 group; the probe is the live measure. Question: how long a job waited
0070 on the catalog.
0071
0072 **Registrar (gauges).** Pending registrations owed and their oldest
0073 age, stashed outputs awaiting their JLab registration, from the
0074 registrar's own record (RUCIO_RESILIENCE.md, Measure 2), and the
0075 registrar's completions in the interval. Question: was the backlog
0076 draining.
0077
0078 **Assessment.** Verdicts: the probe over its timeout or over a
0079 SysConfig latency threshold; the failed share of registrations over a
0080 threshold with at least a floor of attempts; the pending backlog older
0081 than a threshold. The overall verdict is the worst. Publication
0082 follows the maintained-assessment rule: a change in any assessed value
0083 or verdict publishes; a quiet interval affirms.
0084
0085 ## The Catalog view
0086
0087 A focus view, tab `Catalog`, page `Rucio Catalog`, at
0088 `/snapper/epicprod/catalog/`, the
0089 mechanism of the Site, Errors, Platform and Storage views: a
0090 focus-sized cached series over the `catalog` component's snaps, its
0091 own detail rendering, the window, cut, zoom and curve selection every
0092 report page carries; the clean page lands on the last 24 hours.
0093
0094 **Families**, panel order following the question: what was asked,
0095 what came back, how fast, what is owed.
0096
0097 1. *Registrations* — jobs ended per five minutes stacked by
0098 registration outcome: registered, diverted, pending, unfinished,
0099 failed, not reached (the job ended before its registration stage),
0100 no digest (the payload wrote no report: it died before the report
0101 or predates it); one hue per outcome: house state colors where the
0102 outcome is a state (registered blue, pending the warning color,
0103 failed the failure color), green for diverted, purple for
0104 unfinished, the last two solid greys that read on white. A reading covers the interval since the
0105 previous publication, five minutes on the drumbeat and longer
0106 across a missed cycle, so every interval's count is scaled to five
0107 minutes on the curves: a 34-minute interval after a deploy reads as
0108 its rate, not as a seven-fold spike. The cut card keeps the
0109 interval's own count and bounds. One panel per queue under a queue
0110 selector, default all queues summed.
0111 2. *Failed by exit code* — the failed member alone, stacked by payload
0112 exit code and scaled the same way, so a lost registration (1, 81
0113 under payloads before 0.18.1) reads apart from a refused one (78).
0114 3. *Catalog latency* — the probe's three timings as lines in
0115 milliseconds, timeouts drawn at the timeout value in the failure
0116 color; the registration stage's median and 90th percentile from
0117 the reports as a second panel in seconds, where the reports exist.
0118 4. *Registrar* — pending owed and stashed awaiting as bands; the
0119 oldest pending age as a line; completions per bin.
0120
0121 **The cut.** A click renders the catalog's standing at that instant
0122 on the card: the probe timings with the thresholds, the interval's
0123 registration counts and shares with the failed split by exit code and
0124 by queue, the latency figures, the registrar's owed counts and oldest
0125 age, and the verdict chips with the threshold each names.
0126
0127 **Thresholds** are SysConfig keys seeded at their defaults:
0128 `catalog_probe_timeout_s` (10), `catalog_probe_slow_ms` (2000),
0129 `catalog_failed_share` (0.10), `catalog_failed_floor` (20),
0130 `catalog_pending_old_hours` (6).
0131
0132 ## Backfill
0133
0134 The registrations group is reconstructible: the digest is on every
0135 job in the PanDA record. A one-off script
0136 (`scripts/backfill-catalog-intervals.py`, the errors backfill's shape)
0137 writes one synthetic snap per non-empty five-minute interval under
0138 capture policy `backfill-catalog-v1`, reconstructed evidence
0139 distinguishable from observed snaps, carrying the registrations group
0140 and, where the ingested reports allow, the latency group; the probe
0141 and registrar groups are absent in a backfilled snap, as the
0142 reporter's fields are absent before it ran on the platform component.
0143 Idempotent, dry run by default, bounded to intervals before the first
0144 live snap. The first run covers 2026-09-15 onward, so the collapse of
0145 2026-09-16 is on the record end to end.
0146
0147 ## Retrieval
0148
0149 The view's series ride `snapper_series` and the REST series endpoint;
0150 the component's state at any instant answers through
0151 `snapper_state_at` and `snapper_changes_between`.
0152
0153 ## Implementation notes
0154
0155 - `monitor_app/snapper_catalog.py`: the maintainer, registered beside
0156 the platform maintainer in the System-status refresh; the probe's read
0157 as `eicprod` by a token from the PanDA server, else with the production
0158 proxy the refresh doer holds (`swf_epicprod/jlab_auth.py`); the interval
0159 read of the digest (`jobmetrics` regex, one query over the interval's
0160 ended jobs, jobsactive4 and jobsarchived4); the latency read over
0161 `swf_epicprod_jobs`; the registrar read.
0162 - `monitor_app/snapper_providers.py`: curve extraction under the `cat`
0163 prefixes, the families, the focus view declaration with the queue
0164 selector, the card; the focus series cache TTL rule gains the
0165 catalog key class; the series cache version bumps.
0166 - `_snapper_cards.html`: the `catalog` card kind.
0167 - `scripts/backfill-catalog-intervals.py`.
0168 - The alarm: the platform-health alarm's shape on the catalog verdict,
0169 after the component has been observed through one week.
0170 - Order of delivery, each stage usable alone: the component with the
0171 registrations and probe groups and the view's first three families,
0172 then the backfill, then the latency and registrar groups and their
0173 families, then the alarm.
0174
0175 ## Related
0176
0177 - [SNAPPER.md](SNAPPER.md), [SNAPPER_PLATFORM.md](SNAPPER_PLATFORM.md),
0178 [SNAPPER_ERRORS.md](SNAPPER_ERRORS.md), [SNAPPER_STORAGE.md](SNAPPER_STORAGE.md).
0179 - swf-epicprod
0180 [RUCIO_RESILIENCE.md](https://github.com/BNLNPPS/swf-epicprod/blob/main/docs/RUCIO_RESILIENCE.md),
0181 [EPICPROD_PAYLOAD.md](https://github.com/BNLNPPS/swf-epicprod/blob/main/docs/EPICPROD_PAYLOAD.md)
0182 (the digest, exit codes 78, 80, 81, 85).