Long-lived background task that processes diagnostic requests. Active in both push and pull modes. In push mode, the worker pushes the full assembled diagnostic set via `publishDiagnostics`. In pull mode, it pushes only fast diagnostics and caches the full set in `diag_last_full` for the next pull response (see [`assemble_and_push`]). Spawned once during `initialized`. Loops forever, waiting
(&self)
| 1024 | /// immediately after step 4 finishes — giving the two-slot |
| 1025 | /// (one running + one pending) behaviour. |
| 1026 | pub(crate) async fn diagnostic_worker(&self) { |
| 1027 | loop { |
| 1028 | if self.shutdown_flag.load(Ordering::Acquire) { |
| 1029 | return; |
| 1030 | } |
| 1031 | |
| 1032 | // ── Step 1: wait for work ─────────────────────────────── |
| 1033 | self.diag_notify.notified().await; |
| 1034 | |
| 1035 | if self.shutdown_flag.load(Ordering::Acquire) { |
| 1036 | return; |
| 1037 | } |
| 1038 | |
| 1039 | // ── Step 2: debounce ──────────────────────────────────── |
| 1040 | loop { |
| 1041 | let version_before = self.diag_version.load(Ordering::Acquire); |
| 1042 | tokio::time::sleep(std::time::Duration::from_millis(DIAGNOSTIC_DEBOUNCE_MS)).await; |
| 1043 | let version_after = self.diag_version.load(Ordering::Acquire); |
| 1044 | if version_before == version_after { |
| 1045 | // No new edits during the sleep — proceed. |
| 1046 | break; |
| 1047 | } |
| 1048 | // More edits arrived — loop and debounce again. |
| 1049 | } |
| 1050 | |
| 1051 | // ── Step 3: snapshot all pending URIs ──────────────────── |
| 1052 | let uris: Vec<String> = { |
| 1053 | let mut pending = self.diag_pending_uris.lock(); |
| 1054 | std::mem::take(&mut *pending) |
| 1055 | }; |
| 1056 | if uris.is_empty() { |
| 1057 | continue; |
| 1058 | } |
| 1059 | |
| 1060 | // ── Step 4: collect and publish for each URI ──────────── |
| 1061 | // Snapshot content for each URI individually, releasing the |
| 1062 | // read lock before each async publish call so that |
| 1063 | // `did_change` is never blocked. |
| 1064 | for uri in &uris { |
| 1065 | let content = { |
| 1066 | let files = self.open_files.read(); |
| 1067 | match files.get(uri) { |
| 1068 | Some(c) => c.clone(), |
| 1069 | None => continue, |
| 1070 | } |
| 1071 | }; |
| 1072 | self.publish_diagnostics_for_file(uri, &content).await; |
| 1073 | } |
| 1074 | } |
| 1075 | } |
| 1076 | |
| 1077 | // ── PHPStan worker ────────────────────────────────────────────── |
| 1078 |
no test coverage detected