Fluke MET/TEAM — Cutover V1 → V2 (Runbook)¶
Dieses Runbook beschreibt den produktiven Umstieg der MET/TEAM-Synchronisation von calServer V1 (Yii) auf calServer V2 (Laravel) für eine Installation.
Ergänzt die Funktionsübersicht in Fluke MET/TEAM und das
Entwicklungskonzept docs/konzept-metteam-synchronisation-v2.md.
Grundregel: genau ein Sync-Master¶
V1-Cron und V2-Scheduler konsumieren beide destruktiv aus der
MET/TEAM-Tabelle AuditLog2. Laufen beide gleichzeitig, gehen Events verloren
oder werden doppelt verarbeitet (Doppel-Push, Echo-Schleifen).
Deshalb entscheidet ein gemeinsam gelesenes Property, wer der aktive Sync-Master ist:
| Property | Ort | Werte | Default |
|---|---|---|---|
sync_master |
settings/mssql/ (geteilte property-Tabelle) |
v1, v2 |
v1 (leer/unbekannt = v1) |
Wirkung des Flags:
sync_master = v1(oder leer): V1 synchronisiert. V2 steht still — Pull- und Push-Läufe überspringen mit Grundnot_master, und die V2-Outbox stellt nichts in die Warteschlange.sync_master = v2: V2 synchronisiert. Die V1-KonsolenbefehlesyncDataFromMSSQLundtransferToMSSQLstehen sofort still (früher Guard-Return), bevor sie MET/TEAM überhaupt anfassen. Auch die synchronen V1-Pushes aus Web-Requests (Inventar-/Kalibrier-/Ergebnis-Speichern, Löschen, Callsheet-Close, Copy-All-Button) stehen still — eine weiterhin erreichbare V1-UI kann nach dem Cutover nicht mehr als zweiter Schreiber nach MET/TEAM durchgreifen.
Der Default v1 ist bewusst gewählt: Bestandssysteme laufen V1, und V2 darf die
Hoheit nie ohne expliziten Cutover übernehmen. Der schlimmste Fall bei
Fehlkonfiguration ist damit „V2 synchronisiert nicht" (sichtbar und diagnostizierbar) —
niemals „beide gleichzeitig".
Voraussetzungen prüfen (vor dem Cutover)¶
- V2-Verbindung: In der Admin-UI (Admin → Erweiterungen → Fluke MET/TEAM → Verbindung) „Verbindung testen". Muss erfolgreich sein.
- SQL-Server-Treiber:
pdo_sqlsrvmuss auf dem V2-Server installiert sein. Ohne Treiber schlägt der Verbindungstest fehl, bevor MET/TEAM überhaupt erreicht wird. - Provisionierte Schnittstelle: Werkzeuge → Diagnose ausführen und prüfen, dass unter „Objekte fehlend" eine 0 steht. Da V1 und V2 dieselbe provisionierte SP-Schnittstelle nutzen, ist dann keine Neuinstallation nötig; fehlen Objekte, legt „Jetzt provisionieren" neben dem Befund sie an.
!!! danger "Nicht auf provisioning_required: false verlassen"
Der Status vergleicht nur den gespeicherten Stempel. Der bleibt stehen,
wenn jemand in MET/TEAM Prozeduren oder Trigger entfernt — aus dem Feld
gemeldet: Stempel 10, in der Datenbank kein einziges der dreizehn
Objekte. Ein Cutover auf dieser Grundlage übergibt die Hoheit an eine
Seite, die sofort auf „Could not find stored procedure" läuft. Nur die
Diagnose sieht nach.
4. Sync-Flags: Die gewünschten Richtungen (sync_inventory_bidirectional,
sync_calibration_bidirectional, sync_results_bidirectional) sind in V2
identisch zu V1 gesetzt.
Aktuellen Master jederzeit ablesen — in der Oberfläche unter Admin → Erweiterungen → Fluke MET/TEAM → Synchronisation → Sync-Hoheit (Cutover), oder auf der Konsole:
Cutover-Ablauf¶
-
V1-Cron stoppen. Docker-Cron (
run_cron.shbzw. dencron_job-Eintragrun_cron_every_5_seconds) deaktivieren. LaufendeCopy_All_To_METTEAM- Vorgänge abschließen oder stoppen. -
Backlog leerlaufen lassen. Sicherstellen, dass der
AuditLog2-Rückstand von V1 vollständig abgearbeitet (oder bewusst bekannt) ist, bevor V2 übernimmt. -
Passwort migrieren (Klartext → verschlüsselt). Zuerst als Probelauf:
Der Klartext bleibt dabei erhalten — er wird für einen möglichen Rollback noch gebraucht. (V2 liest den Klartext ohnehin als Fallback; die Migration stellt sicher, dass V2 anschließend eine eigene verschlüsselte Kopie besitzt.)
- Sync-Master auf V2 umschalten. In der Oberfläche unter Admin → Erweiterungen → Fluke MET/TEAM → Synchronisation → Sync-Hoheit (Cutover) auf „An V2 übergeben"; der Bestätigungsdialog nennt offene Voraussetzungen (fehlende Verbindung, veraltete Provisionierung, deaktivierte Synchronisation). Gleichwertig auf der Konsole:
Ab hier stehen die V1-Sync-Befehle still (Guard-Return), und V2 gibt Pull/Push frei.
!!! note "Warnung, kein Riegel"
Weder die Oberfläche noch der Konsolenbefehl verweigern das Umschalten,
wenn eine Voraussetzung fehlt. Das ist Absicht: ein harter Riegel
verbaute den Rückweg auf v1 in genau der Lage, in der man ihn braucht.
- Verknüpfungen abgleichen (
metteam:relink). Vor dem ersten V2-Push jede Assetnummer gegen den MET/TEAM-Bestand fahren — zuerst als Bericht, dann mit--apply:
docker exec calserver-api-v2 php artisan metteam:relink
docker exec calserver-api-v2 php artisan metteam:relink --apply
Der Abgleich adoptiert Geräte, die in MET/TEAM bereits unter ihrer
Assetnummer (Assets.cID = I4201) existieren, als Verknüpfung — genau die
Prüfung, die V1 vor jedem Push implizit gemacht hat. Ohne diesen Schritt
sah ein Bestand mit verlorenen Verknüpfungen für V2 wie „nie
synchronisiert" aus, und das erste Feld-Update legte das Gerät in MET/TEAM
ein zweites Mal an. Der Bericht meldet außerdem Nummern, die in MET/TEAM
auf ein anderes Asset zeigen (Dubletten/Umnummerierungen) — diese
Fälle vor dem Aktivieren des Push klären. Der Push prüft die Nummer seit
diesem Abgleichsbefehl zusätzlich bei jedem Anlegen selbst; metteam:relink
macht die Lage aber VOR dem ersten Lauf sichtbar.
- V2-Scheduler aktivieren. Sicherstellen, dass der Laravel-Scheduler läuft
(
php artisan schedule:workbzw. der Cron-Eintrag* * * * * php artisan schedule:run). Pull und Push laufen darüber im konfigurierten Intervall; Circuit Breaker und Sperren verhindern Überlappung.
Verifikation nach dem Cutover¶
- Status-Endpoint
/api/v2/metteam/status:sync_master: "v2",is_sync_master: true,provisioning_required: false. - Sync-Protokoll (
/api/v2/metteam/sync-logs, Tab „Protokoll"): frische Pull-/Push-Einträge, keine wiederkehrenden Fehler. - Manueller Probelauf (optional):
php artisan metteam:pullundphp artisan metteam:pushmelden verarbeitete Einträge statt einesskipped-Grunds.
Rollback¶
Solange das Klartext-Passwort noch vorhanden ist, ist der Rückweg jederzeit gefahrlos möglich — in der Oberfläche über „An V1 zurückgeben", oder:
Der Rückweg gilt nur für die Primär-Instanz: nur sie teilt sich die Einstellung mit V1. Weitere Instanzen sind V2-only — dort steht kein V1, das übernehmen könnte, deshalb bieten Oberfläche und API das Zurückgeben gar nicht erst an (die API antwortet mit 409).
Anschließend den V1-Cron wieder aktivieren. V2 fällt sofort in den Zustand
not_master zurück und stellt nichts mehr in die Outbox; V1 übernimmt wieder.
Endgültige Bereinigung (erst nach Bewährung)¶
Wenn V2 dauerhaft stabil läuft und V1 endgültig außer Betrieb ist, kann der Klartext des Passworts entfernt werden (behebt Schwachstelle S1 aus dem Konzept):
Kein Rollback mehr ohne erneute Passworteingabe
Nach dem Leeren des Klartexts kann ein reaktivierter V1-Sync sich nicht mehr mit MET/TEAM verbinden. Diesen Schritt erst ausführen, wenn ein Rückweg auf V1 ausgeschlossen ist.
Testkonzept (Phase 5)¶
Der Cutover-Mechanismus ist vollständig automatisiert getestet (sqlite,
FakeMetteamGateway — kein MSSQL nötig):
| Bereich | Test | Datei |
|---|---|---|
| Master-Default & Umschalten | MetteamSettingsTest (sync_master_defaults_to_v1, …_handed_to_v2, …_handed_back_to_v1, unknown_…_treated_as_v1) |
tests/Unit/Services/MetteamSettingsTest.php |
| V2 steht still (Pull/Push) | test_it_skips_when_v2_is_not_the_sync_master |
tests/Unit/Services/MetteamPullServiceTest.php, …/MetteamPushServiceTest.php |
| Keine Outbox-Enqueues | test_nothing_is_enqueued_when_v2_is_not_the_sync_master |
tests/Unit/Services/MetteamOutboxTest.php |
| Cutover-Befehl | MetteamSyncMasterCommandTest (setzen, zurücksetzen, ungültig, No-op, Abbruch) |
tests/Feature/Console/MetteamSyncMasterCommandTest.php |
| Cutover-Endpoint | MetteamControllerTest (umschalten und zurück, ungültiger Wert, Rechteprüfung, und dass das Settings-Formular die Hoheit nicht umlegen kann) |
tests/Feature/Api/V2/MetteamControllerTest.php |
| Cutover je Instanz | MetteamInstanceControllerTest (Primär schreibt die geteilte Property; Zeilen-Instanz kann nicht auf v1) |
tests/Feature/Api/V2/MetteamInstanceControllerTest.php |
| Warnungen vor der Übergabe | metteamHandoverWarnings (fehlende Verbindung, veraltete Provisionierung, deaktivierter Sync) |
frontend-v2/utils/metteam.test.ts |
| Passwort-Migration | MetteamMigratePasswordCommandTest (migrieren, idempotent, dry-run, überschreiben, purge, Abbruch) |
tests/Feature/Console/MetteamMigratePasswordCommandTest.php |
| Status-Ausgabe | test_status_reports_the_sync_master |
tests/Feature/Api/V2/MetteamControllerTest.php |
Der V1-Guard ist als früher Return in SyncDataFromMSSQLCommand::actionRun() und
TransferToMSSQLCommand::actionRun() implementiert (Property-Lesung
property()->get('settings','mssql','sync_master')); er greift nur bei
=== 'v2' und lässt Bestandsinstallationen (leerer Wert) unverändert.