Repository navigation
fix(incidents): fail over to ICNF when the ANEPC feed is frozen (#42) - #43
Conversation
The OcorrenciasSite feed can keep answering 200 with a frozen snapshot. Every run re-wrote the stale records and CheckIsActive deactivated every fire only ICNF knew about, so new fires disappeared from the endpoints. - AnepcFeedHealth tracks the newest DataDosDados in Redis; stale after ANEPC_STALE_MINUTES (default 30). Transitions go to Discord, replacing the dead history.json tracker. - While stale, ProcessOcorrenciasSite skips writes and CheckIsActive, and ProcessICNFNewFireData owns the active flag: ICNF-only fires follow ICNF (Dominado only within 24h), ANEPC fires close on Extinto. - Incidents carry source=anepc|icnf; when ANEPC returns it overwrites them and CheckIsActive resumes as before. - ICNFTool shares the faztable.asp fetch/parse between both jobs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 72787d48b6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ($icnfOnly) { | ||
| // ICNF owns the lifecycle: brings back fires that were dropped | ||
| // because a frozen ANEPC list did not include them. | ||
| if ((bool) $incident->active !== $icnfActive) { | ||
| $incident->active = $icnfActive; |
There was a problem hiding this comment.
Reconcile ICNF reactivation with fresh ANEPC cleanup
When ANEPC is fresh or has recovered, CheckIsActive::handle() still deactivates every incident absent from its ANEPC list, including ICNF-only incidents. This branch then reactivates those same incidents on the next ICNF run even though $anepcStale is false. Both ingestion jobs run every five minutes in bootstrap/app.php, so existing ICNF-only fires now repeatedly disappear and reappear depending on job execution order, rather than settling under one source's authority. Make the two jobs agree on lifecycle ownership while ANEPC is fresh.
Useful? React with 👍 / 👎.
| if (AnepcFeedHealth::isStale()) { | ||
| Log::info('CheckIsActive: ANEPC feed is stale, skipping'); | ||
|
|
||
| return; |
There was a problem hiding this comment.
Scope the stale-feed guard to the snapshot's actual source
When the ArcGIS feed is stale or its health cache has not been initialized, this guard also disables cleanup for the separate ANEPC_API_URL ingestion path. The registered SyncANEPCIncidents command runs ProcessANPCAllDataV2, which dispatches CheckIsActive with its successfully fetched list but never records anything in AnepcFeedHealth. Consequently, running anepc:sync can update current incidents while leaving absent incidents active indefinitely, even when that alternative feed is healthy. Pass the snapshot source or freshness into the cleanup job instead of unconditionally applying ArcGIS health to both callers.
Useful? React with 👍 / 👎.
Closes #42
Closes #44
Problem
ProcessOcorrenciasSite(ArcGIS OcorrenciasSite) answers 200 but its data has been frozen since 2026-10-25 00:58 UTC (DataDosDados). Every 5 min it re-wrote the same 32 records and dispatchedCheckIsActivewith that list, which deactivated every fire created byProcessICNFNewFireData. The ICNF job never touchedactive, so those fires never came back. Thehistory.jsonfreshness tracker was dead (file never written).Change
App\Support\AnepcFeedHealth— tracks newestDataDosDados(hash fallback) in Redis. Stale afterANEPC_STALE_MINUTES(default 30). Posts to Discord on stale/recovered transitions.ProcessOcorrenciasSite— while stale, does not write the frozen snapshot nor dispatchCheckIsActive. Setssource=anepc+anepcUpdatedAt.CheckIsActive— skips if the feed is stale (defensive, it is queued).ProcessICNFNewFireData— ICNF is primary for ICNF-only incidents, and for all incidents while ANEPC is stale:activefollows ICNF (Em Curso→ active,Dominado→ active only if started < 24h ago,Extinto→ inactive). Re-activates fires wrongly dropped.Extinto, never re-opened.source=icnf.ProcessOcorrenciasSitenow runs every 2 minutes (was 5).App\Tools\ICNFTool— shared fetch/parse offaztable.asp(was duplicated).source=anepc) andCheckIsActivedeactivates anything not in its list → ANEPC is primary again.Tests
tests/Unit/Support/AnepcFeedHealthTest.php,tests/Unit/Tools/ICNFToolTest.php(9 tests, pass).main(missingmongodbextension in the local container).faztable.asp: 8892 Extinto / 37 Dominado / 8 Em Curso → 12 considered active (old Dominados excluded).Deploy
php artisan queue:restart(jobs changed).ANEPC_STALE_MINUTESin.env(default 30). No migrations.ProcessOcorrenciasSiterun the feed is flagged stale (Discord message); on the nextProcessICNFNewFireDatarun (≤5 min) the ICNF fires reappear. To force:php artisan ocorrencias:syncthen runProcessICNFNewFireData.🤖 Generated with Claude Code