Der CircleCI Cache Key Bug, der stillschweigend Ihren Builds stale Abhängigkeiten dient
The CircleCI Cache Key Bug That's Silently Serving Your Builds Stale Dependencies
Ihre CircleCI-Pipeline ist grün. Jeder Job geht vorbei. Und doch läuft Ihre App gegen eine Abhängigkeitsversion, die seit einem Monat nicht mehr ausgeliefert wurde - niemand hat es begangen, niemand hat es gestoßen, es ist einfach leise in der Produktion aufgetaucht. Wenn Sie einen Fehler wie diesen gejagt haben, ist der Schuldige fast nie Ihr Code. Es ist dein Cache-Key. Dies ist eine fünfminütige Lektüre und eine fünfzehnminütige Korrektur. Quick win friday, bereitgestellt für ihre. Das Abhängigkeits-Caching des Fehlermodus CircleCI funktioniert mit einem einfachen Vertrag: Sie berechnen einen Schlüssel aus etwas, das sich ändert, wenn sich Ihre Abhängigkeiten ändern (normalerweise eine Lockfile-Prüfsumme), und Sie speichern / wiederherstellen einen Cache, der an diesen Schlüssel gebunden ist. Der Vertrag bricht auf drei spezifische, äußerst häufige Weise: Sie überprüfen die falsche Datei. Sieht vernünftig aus, bis jemand eine transitive abhängigkeit über ohne...
Ihre CircleCI-Pipeline ist grün. Jeder Job geht vorbei. Und doch läuft Ihre App gegen eine Abhängigkeitsversion, die seit einem Monat nicht mehr ausgeliefert wurde - niemand hat es begangen, niemand hat es gestoßen, es ist einfach leise in der Produktion aufgetaucht. Wenn Sie einen Fehler wie diesen gejagt haben, ist der Schuldige fast nie Ihr Code. Es ist dein Cache-Key. Dies ist eine fünfminütige Lektüre und eine fünfzehnminütige Korrektur. Quick win friday, bereitgestellt für ihre. Das Abhängigkeits-Caching des Fehlermodus CircleCI funktioniert mit einem einfachen Vertrag: Sie berechnen einen Schlüssel aus etwas, das sich ändert, wenn sich Ihre Abhängigkeiten ändern (normalerweise eine Lockfile-Prüfsumme), und Sie speichern / wiederherstellen einen Cache, der an diesen Schlüssel gebunden ist. Der Vertrag bricht auf drei spezifische, äußerst häufige Weise: Sie überprüfen die falsche Datei. Sieht vernünftig aus, bis jemand eine transitive abhängigkeit durchstößt, ohne sich zu berühren. Die Prüfsumme bewegt sich nicht. CircleCI gibt glücklich die letzte Woche zurück. tut Präfix-Matching, und die Leute denken, dass es genau passt. CircleCI versucht Ihren Primärschlüssel zuerst, fällt dann durch, und der erste ist ein Präfix-Match gegen bestehende Cache-Einträge - nicht "geben Sie mir die neueste genaue Übereinstimmung." Wenn Ihre restore keys-Liste zu grob ist (z. B. nur ), können Sie einen Cache wiederherstellen, der aus einem völlig anderen Branch mit einer völlig anderen Lockfile erstellt wurde, und der Job wird nicht fehlschlagen. Es wird nur leise nichts installieren (Cache-Hit, sieht die Module sind "dort") oder gegen die falschen Versionen laufen. Es gibt keine Version Escape Luke. Wenn Sie zwangsläufig den Cache eines jeden zwingen müssen, ihn zu ungültig zu machen - einen beschädigten Cache-Eintrag, eine Paketmanager-Migration, eine Änderung des Lockfile-Formats - gibt es keinen billigen Weg, da das Schlüsselformat nie mit einem manuellen Buster entwickelt wurde. Jeder von ihnen scheitert stillschweigend. Kein rotes X. Kein Fehler in den Protokollen. Nur ein Build, der mit veraltetem Zustand lief, und ein Fehlerbericht drei Tage später, den niemand lokal reproduzieren kann, weil lokal in Ordnung ist. Die Korrektur Ersetzen Sie, was auch immer Ihr aktueller Cache-Block mit dieser Form aussieht: Vier spezifische Änderungen, die jeweils einen der oben genannten Fehlermodi beheben: Prüfen Sie die Lockfile, nicht das Manifest. / / / - was auch immer Ihre gelösten Versionen tatsächlich anheftet. Das ist die einzige Datei, bei der "nichts geändert" eine echte Aussage über Ihren Abhängigkeitsbaum ist. (oder , oder ) als Installationsbefehl, immer. Dies ist das Sicherheitsnetz für die Fehlermodi, die Sie noch nicht behoben haben: Wenn der Cache etwas Altes wiederhergestellt hat, weigert sich eine eingefrorene Installation, stillschweigend mit einer nicht übereinstimmenden Sperrdatei fortzufahren, anstatt sie stillschweigend in Einklang zu bringen. Du willst, dass dieser Job rot wird, nicht grün mit dem falschen Baum. Bestellen Sie von den meisten bis zu den am wenigsten spezifischen, und stoppen Sie eine Ebene kurz vor "matches anything". Branch-scoped exakte Übereinstimmung ersten, branch-scoped Präfix zweitens, globale Präfix zuletzt als echte letzte Ausweg für eine brandneue Niederlassung. Haben Sie nicht nur als einzigen Fallback - das ist die Linie, mit der ein Branch einen Cache mit einer anderen Lockfile vollständig wiederherstellen kann. Bump die führende Version Token ( → ) wann immer Sie eine saubere Schiefer benötigen. Dies ist Ihr manueller Cache-Buster. Da es in den Schlüssel selbst eingebacken ist, ist die Erzwingung der Ungültigkeit für alle eine einzeilige PR, kein Support-Ticket für CircleCI oder eine Reise durch die Projekteinstellungen Benutzeroberfläche, um Nuke-Caches von Hand zu erstellen. Verifizieren, dass es tatsächlich funktioniert hat Versenden Sie nicht nur die YAML-Änderung und vertrauen Sie ihr. Fügen Sie einen einzeiligen Assertions-Jobschritt für eine Woche hinzu, während Sie das Verhalten bestätigen: Passen Sie den Paketnamen an die Abhängigkeit an, die Sie zuvor gebissen haben, oder was auch immer Ihr Team am meisten wissen möchte, dass die falsche Version ausgeliefert wurde. Wenn dieser Grep jemals fehlschlägt, sind Ihr Cache und Ihre Lockfile auseinandergegangen - und jetzt versagt sie laut, in CI, anstatt leise, in der Produktion. Die Monorepo-Falle Wenn Sie sich in einem Yarn/npm-Arbeitsbereich oder einem Monorepo mit mehreren Lockfiles befinden, hascht die Prüfsummenfunktion nur das, was Sie ihr mitteilen. In der Repo-Root wird keine Änderung an den eigenen Abhängigkeiten eines Workspace-Pakets vorgenommen, es sei denn, Ihr Paketmanager schreibt diese Auflösung zurück in die Root-Lockfile (die meisten tun dies, aber überprüfen Sie sie für Ihre). Wenn Sie verschachtelte Lockfiles haben, die nicht