apps/api/src/store-providers/ parses store responses, so a break is one module, not the application. Historical data is never lost. Collection pauses, it does not roll back.
This page is what to do between the break and the fix.
Symptoms
In the order a user meets them:- Rankings stop advancing. The most recent date on the keyword monitor stays fixed while the calendar moves.
- The health badge in the header turns amber and names a failed job count.
- Failed jobs accumulate in the queue dashboard at
/admin/queues. - No alerts fire. This is the most misleading symptom, and it is worth stating plainly: alerts are generated from captured data, so when nothing is captured, nothing alerts. Silence is not health.
Triage
Three causes look identical from the outside. This tells them apart.1
Read the failure count
failedJobs counts the App Store, Google Play and alert queues together. A non zero value that keeps climbing across daily runs is the signal. A single failure that clears on retry is not an incident.2
Open a failed job and read its message
Go to The store, the provider method and the original message are all there. Note the method: it names the parser to start from.
/admin/queues, choose the failed set, and read failedReason. Every store failure is wrapped the same way, which makes the message the primary evidence:3
Classify it
The distinguishing signal for a parser break is that it is confined to one store and the messages are structural rather than transport. Both stores failing at once is almost always rate limiting or a network problem, because Apple and Google do not change their markup on the same night.
Containment
What to do immediately, without waiting for a fix.- Failed jobs do not block the queue. The natural assumption is the opposite, so it is worth being explicit: each app, keyword and category is its own job. A job that fails is retried with backoff and then set aside, and the rest of the run continues. If Google Play is broken, the App Store still collects that night.
- Nothing is lost. Every position, review and snapshot already captured stays exactly as it was. A break pauses collection.
- Decide whether to pause the daily run. Leaving it on against a broken parser spends rate limit budget on requests that cannot succeed and fills the failed set. If the break is confirmed and a fix is days away, set
CRON_DAILYto a schedule that will not fire, restart the API, and put it back afterwards. If a fix is hours away, leave it alone. - Clear the failed set once resolved. Retry the failed jobs from
/admin/queuesif the day still matters, or discard them if the next daily run will cover it. Retrying a rank check for a date that has passed captures today’s SERP under today’s date, not the missed one.
Recovery
For whoever ships the fix.1
Reproduce outside the application
Confirm whether the fault is the scraper library or the integration:It is opt in and never runs in CI. See Check the parsers directly.
2
Check upstream
Look for an open issue or a release on the library the failing store uses. An upstream fix is usually a dependency bump rather than a code change here.
3
Change one module
Only the provider directory needs to change. Start from the file for the failing store, and the method the failed job named.
4
Ship it with a regression test
Build the test from the captured raw payload, so it fails for the reported reason before the fix and passes after. Commit as
fix(providers).Reprocess history from stored payloads
Raw scraper responses are stored inraw JSON columns precisely so a corrected parser can be re-run over them. Nobody would guess this is available, so it is worth saying: AppSnapshot.raw holds the full store response for every snapshot ever captured.
That means a parser bug which mapped a field wrongly, rather than one which failed outright, can be corrected retroactively. Re-read the stored payload and rewrite the derived columns. A parser that threw captured nothing, so there is nothing to reprocess for those days.
Backfill
Whether the missed days come back, honestly:
The honest summary is that a gap in ranking history stays a gap. Charts will show it. This is inherent to observing a search result rather than being handed a dataset.
Check the parsers directly
One command that answers “is the parser working right now” without running the pipeline or waiting for cron:SMOKE_PROVIDERS=1 is set. CI never runs it, because a build must not depend on a third party.
Related
The daily pipeline and rate limits
Why both workers run at concurrency 1.
Health checks and monitoring
Where the failed job count comes from.