Zum Inhalt

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 Grund not_master, und die V2-Outbox stellt nichts in die Warteschlange.
  • sync_master = v2: V2 synchronisiert. Die V1-Konsolenbefehle syncDataFromMSSQL und transferToMSSQL stehen 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)

  1. V2-Verbindung: In der Admin-UI (Admin → Erweiterungen → Fluke MET/TEAM → Verbindung) „Verbindung testen". Muss erfolgreich sein.
  2. SQL-Server-Treiber: pdo_sqlsrv muss auf dem V2-Server installiert sein. Ohne Treiber schlägt der Verbindungstest fehl, bevor MET/TEAM überhaupt erreicht wird.
  3. 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:

docker exec calserver-api-v2 php artisan metteam:sync-master
# => Current MET/TEAM sync master: v1

Cutover-Ablauf

  1. V1-Cron stoppen. Docker-Cron (run_cron.sh bzw. den cron_job-Eintrag run_cron_every_5_seconds) deaktivieren. Laufende Copy_All_To_METTEAM- Vorgänge abschließen oder stoppen.

  2. Backlog leerlaufen lassen. Sicherstellen, dass der AuditLog2-Rückstand von V1 vollständig abgearbeitet (oder bewusst bekannt) ist, bevor V2 übernimmt.

  3. Passwort migrieren (Klartext → verschlüsselt). Zuerst als Probelauf:

php artisan metteam:migrate-password --dry-run
php artisan metteam:migrate-password

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.)

  1. 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:
docker exec calserver-api-v2 php artisan metteam:sync-master v2

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.

  1. 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.

  1. V2-Scheduler aktivieren. Sicherstellen, dass der Laravel-Scheduler läuft (php artisan schedule:work bzw. 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:pull und php artisan metteam:push melden verarbeitete Einträge statt eines skipped-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:

docker exec calserver-api-v2 php artisan metteam:sync-master v1

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):

php artisan metteam:migrate-password --purge-plaintext

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.