Dieser simple Austausch war ein Kinderspiel, der weit aufwendigere Code "unter der Haube" hingegen wurde in den vergangenen Wochen massiv verbessert, in vielerlei Hinsicht besser abgesichert, auf Sonderfälle vorbereitet, und die Logik der "Offset"-Spiele (also der auf andere Termine verschobenen Spiele) wurde gefixt, die hatte nämlich nicht so funktioniert wie gewollt.
Wenn ich die Zeit finde, werde ich noch das eine oder andere Wort dazu verlieren, jetzt hoffe ich, dass zum Saisonstart erstmal alles so funktionieren wird wie aufwendig offline getestet und geplant (und dass uns die Datenquelle nicht im Stich lässt).
Na ja, geht so … Dieses Thema Live-Tabelle wird zunehmend zu einem IT-Megaprojekt. Klingt ja eigentlich einfach: Daten einsammeln, aufbereiten und hübsch darstellen. Wobei die reine Darstellung nochmal ein Thema für sich ist, an dem wir diese Saison noch gar nichts gemacht haben, aber bis auf wenige Ausnahmen passt das ja auch für den Moment.
Vermutlich wird niemand etwas von den ganzen Problemen im Hintergrund bemerkt haben, und so soll es ja auch sein. Aber damit es so ist, ist bei der DEL2 ein Vielfaches des Aufwands wie bei der DEL nötig. Die gelieferten Daten sind manchmal dermaßen inkonsistent, dass es einem schwindlig werden kann.
Aber dazu mehr und im Detail im unteren Teil dieses Posts, andere Änderungen betreffen wie oben erwähnt den rein technischen Ablauf "unter der Haube", und damit fangen wir mal an. Dieser Beitrag richtet sich an diejenigen, die das Ganze vielleicht auch technisch ein wenig interessiert.
Eine Vorbemerkung: Wir haben bisher nur eine Datenquelle (wir nennen sie hier Datenquelle[1]) verwendet, die zwar halbwegs (!) zuverlässig, aber auch elend lahmarschig war. Als das Spiel der DEG in Landshut am 2. Spieltag im sporteurope-Stream längst beendet war, hat es geschlagene 10 Minuten gedauert, bis unsere Live-Tabelle bei der DEG von 4 auf 5 Punkte und somit Platz 2 gesprungen ist. Ein solches Verhalten verdient den Begriff "Live-Tabelle" nur mit sehr viel Wohlwollen.
Wir verwenden jetzt (aber erstmal nur in einem parallelen "Shadow-Test") eine zweite Datenquelle (wir nennen sie hier Datenquelle[2]), die deutlich schnellere Ergebnisse liefert, aber auch komplizierter auszuwerten ist, weil dazu für den kompletten Spieltag nicht nur ein einziger Datensatz, sondern für jedes Spiel jeweils ein separater Datensatz ausgewertet werden muss (also in der Regel sieben pro Spieltag). Zudem ist auch diese Datenquelle nur bedingt zuverlässig: In einem Fall wurde am 1. Spieltag beim Spiel Weißwasser vs. Landshut das erste Drittel komplett "vergessen", es wurden also überhaupt keine Ergebnisse des ersten Drittels geliefert und erst 40 Minuten nach Spielbeginn in der Drittelpause "nachgespult".
Das alles miteinander abzugleichen und sowohl schnelle als auch korrekte Ergebnisse zu liefern, darin besteht die schwierige Aufgabe. Fun fact am Rande: Selbst die offizielle DEL2-App hat beim Spiel Dresden vs. Kassel am 1. Spieltag zwischenzeitlich die falschen Ergebnisse 0:4 und 0:5 angezeigt, als es in Wirklichkeit noch 0:3 bzw. 0:4 stand (siehe → hier und folgende). Den Grund konnten wir anhand unserer Logfiles leicht erkennen: Die Tore von Brendan O’Donnell zum 0:3 und von Jimmy Martinovic zum 0:4 waren an der eigentlichen Ur-Quelle jeweils doppelt erfasst worden. Dass solche Fehler sogar bis in die Apps durchschlagen, beweist, dass letztlich (fast) alle auf dieselben Daten zugreifen, nur auf unterschiedlichen Wegen. Ob z.B. FlashScore genau diesen Fehler auch gezeigt hat, wissen wir allerdings nicht.
Jedenfalls fangen wir solche Fälle zukünftig ab. Es KÖNNTE also sein, dass bei zukünftigen Fällen dieser Art unsere Anzeige stimmt, die der anderen aber nicht. 
Okay, nun die ausführlicheren Details hinter den Spoilern:
1. Changelog: Was vor Saisonbeginn an der Live-Tabelle überarbeitet wurde
Technische Überarbeitung der DEL2-Live-Tabelle zur Saison 2026/27
Im Hintergrund wurde die Live-Tabelle vor Saisonbeginn an mehreren Stellen grundlegend überarbeitet. Nach außen sieht sie exakt aus wie bisher, intern wurden aber einige Fehlerquellen und bisherige Sonderfälle beseitigt bzw. deutlich besser abgesichert:
- Start- und Ablaufsteuerung komplett neu aufgebaut: Der eigentliche Dienst läuft jetzt über einen stabilen Rahmenprozess; die veränderliche Logik wird bei jedem Durchlauf neu geladen. Änderungen können dadurch kontrollierter vorgenommen werden, ohne jedes Mal den gesamten Dienst neu starten zu müssen.
- Sauberes Saisonende: Früher hätte der Server den Prozess durch die verwendete Neustartlogik auch nach einem gewollten Saisonende immer wieder gestartet. Jetzt kann sich die Live-Tabelle nach dem letzten Spieltag regulär beenden und bleibt auch beendet.
- Fehlender oder fehlerhafter Spielplan kann keinen Schaden mehr anrichten: Ist die Spielplan-Datei nicht vorhanden oder ungültig, startet die eigentliche Tabellenlogik gar nicht erst. Bestehende Tabellenstände, Vergleichsdaten und Statusdateien werden dabei nicht verändert.
- Sauberer Saisonstart: Veraltete Vergleichsdaten aus der Vorsaison werden vor Saisonbeginn entfernt. Gleichzeitig wurde verhindert, dass unmittelbar vor dem ersten Bully Statuswerte versehentlich wieder zurückgesetzt werden.
- Weniger unnötige Server- und Netzwerkzugriffe: Während der Vorsaison läuft nicht mehr permanent die komplette PHP-/Abruflogik. Die eigentliche Arbeit beginnt erst kurz vor dem ersten Saisonspiel.
- Technische Zustände werden getrennt behandelt: Vorsaison, normaler Leerlauf, Live-Betrieb, fehlender Spielplan sowie PHP-/Statusfehler und Saisonende sind jetzt unterscheidbare Zustände. Wiederholte identische Meldungen werden nicht ständig ins Log geschrieben.
- Ein Spieltag gilt nicht mehr allein deshalb als beendet, weil irgendwo „Spielende“ steht: Alle Spiele müssen ein verwertbares und entschiedenes Ergebnis besitzen. Ein 2:2 mit Endmarkierung oder ein noch nicht vorhandenes Ergebnis reicht ausdrücklich nicht aus; Verlängerung und Penaltyschießen werden getrennt erkannt.
- Neue Plausibilitätsprüfung beim Spieltagsende: Wenn alle Spiele beendet sind, wird zusätzlich nachgerechnet, welche Auswirkungen die Ergebnisse auf Spiele, Siege/Niederlagen, Tore, Tordifferenz und Punkte haben müssen. Erst wenn das mit der gelieferten Gesamttabelle übereinstimmt, wird der Spieltag normalerweise abgeschlossen. Damit kann eine bereits fertige Ergebnisliste nicht mehr versehentlich zusammen mit einer noch veralteten Tabelle archiviert werden. Die frühere pauschale Wartezeit von 30 Minuten ist dadurch entfallen.
- Ein bereits abgeschlossener Spieltag springt nicht wieder auf „live“: Dafür gibt es jetzt einen eigenen Abschlussmarker. Das war nötig, weil das maximale technische Zeitfenster noch länger geöffnet sein kann, obwohl alle Spiele längst korrekt verarbeitet wurden.
- delta_rank bei verlegten Spielen korrigiert: Vor- und Nachholspiele werden hinsichtlich der Platzierungsänderungen jetzt weiterhin auf die richtige vorherige Vergleichsbasis bezogen. Auch mehrere solcher „Offset“-Spiele hintereinander und der anschließende reguläre Spieltag werden korrekt behandelt.
- Erster Spieltag ohne Altlasten: Am 1. Spieltag starten alle Platzierungsänderungen bewusst bei 0; Daten aus der Vorsaison fließen nicht mehr als vermeintliche Vergleichsbasis ein.
- Zusätzliche Quellen- und Diagnoseprüfungen: Unterschiedliche Zustände der beiden bisher verwendeten Datenansichten werden erkannt und protokolliert. Das hilft insbesondere dabei, Verzögerungen und kurzfristig widersprüchliche Datenlieferungen nachvollziehen zu können.
- Umfangreiche Regressionstests: Der zum Saisonstart eingesetzte PHP-Stand wurde zuletzt mit 48/48 erfolgreichen Integrationstests geprüft, darunter reguläre Spieltage, verlegte Spiele, mehrere Verlegungen hintereinander und die anschließende Rückkehr zum normalen Spieltagsbetrieb.
Eine maximale zeitliche Notbremse existiert weiterhin als Sicherheitsnetz. Schon vor Saisonstart war außerdem bekannt, dass keine lokale Plausibilitätsprüfung erkennen kann, wenn eine externe Quelle und deren Tabelle denselben falschen, aber untereinander konsistenten Stand liefern. Genau dieser theoretische Grenzfall ist am 1. Spieltag tatsächlich aufgetreten.
2. Erkenntnisse aus den ersten beiden Spieltagen und geplante weitere Änderungen
Was die ersten beiden Spieltage gezeigt haben
Die ersten beiden echten Spieltage waren gleichzeitig ein guter Belastungstest. Die Live-Tabelle selbst hat grundsätzlich funktioniert, allerdings haben die Datenquellen einige interessante Eigenheiten gezeigt, die wir jetzt für die nächste Ausbaustufe berücksichtigen wollen:
- Externe Live-Daten sind nicht immer „monoton“: Ein bereits gemeldeter Spielstand kann wieder zurückspringen, ein als beendet gemeldetes Spiel wieder auf „live“ wechseln und wenige Sekunden später erneut beendet sein. Besonders bei Datenquelle[1] konnten solche Wechsel mehrfach beobachtet werden.
- Am 1. Spieltag wurden bei Dresden vs. Kassel zeitweise Tore doppelt gemeldet. Dadurch entstanden vorübergehend falsche Zwischenstände. Auch Datenquelle[2] ist also nicht grundsätzlich fehlerfrei; eine schnellere Quelle darf nicht automatisch mit einer immer richtigen Quelle gleichgesetzt werden. Genau solche Duplikate wurden deshalb beim zweiten Test bereits gezielt als Anomalie überwacht.
- Beim Spiel Lausitzer Füchse vs. Landshut trat der bislang kritischste Sonderfall auf: Nach der Schlusssirene wurde noch ein technisches Tor zum 1:3 zugesprochen. Verschiedene Datenansichten lieferten danach zeitweise 1:2 bzw. 1:3; im Produktionslog waren beide Stände unmittelbar gegeneinander zu sehen. Später waren Ergebnis und Gesamttabelle gemeinsam auf dem falschen bzw. veralteten Stand 1:2 – und damit intern völlig plausibel. Die bisherige Tabellenprüfung konnte diesen Fall folgerichtig nicht erkennen und der Stand musste anschließend korrigiert werden.
- Shootouts sind ein weiterer Sonderfall: Am 2. Spieltag meldete Datenquelle[1] beispielsweise EV Landshut vs. DEG bereits mit 5:5 n.P. als beendet, obwohl der entscheidende Shootout-Treffer zum 5:6 noch nicht verarbeitet war. Unsere bestehende Sicherung, ein unentschiedenes Endergebnis nicht zu akzeptieren, hat hier einen verfrühten Abschluss verhindert. Der korrekte Stand 5:6 erschien dort erst später.
- Datenquelle[2] war insgesamt deutlich schneller: Besonders auffällig war erneut EVL vs. DEG. Datenquelle[2] hatte die DEG bereits um 19:41:56 Uhr mit 5 Punkten, die entsprechende Tabelle bei Datenquelle[1] erst um 19:51:26 Uhr – also rund 9½ Minuten später.
- Auch Datenquelle[2] hatte allerdings kurzzeitige technische Aussetzer. Deshalb soll auch die neue Lösung nicht einfach blind eine einzige Quelle übernehmen, sondern den letzten gültigen Stand behalten, erneut versuchen und bei Bedarf auf einen anderen Endpunkt ausweichen.
- Geplant ist deshalb eine neue Quellenlogik: Datenquelle[2] soll voraussichtlich die primäre Quelle für die aktuelle Tabelle werden. Datenquelle[1] bleibt als Kontroll- und Ersatzquelle erhalten und kann unter anderem dann zur Unterscheidung von Verlängerung und Penaltyschießen herangezogen werden, sollte der entsprechende Spielverlauf bei Datenquelle[2] nicht vollständig beobachtet worden sein können. Bei echten Konflikten soll ggf. mit FlashScore eine weitere, möglichst unabhängige Prüfinstanz hinzukommen (daran basteln wir noch).
- Aktuelle Anzeige und endgültiger Spieltagsabschluss werden stärker getrennt: Ein schneller und plausibler neuer Tabellenstand soll künftig sofort angezeigt werden können. Bevor daraus aber der endgültige Vergleichsstand für den nächsten Spieltag und ein Archivstand erzeugt werden, soll eine zusätzliche Verifikationsphase mehrere stabile Zustände bzw. die Kontrollquellen abwarten.
- Die Tabellenplätze können/werden wir künftig selbst bestimmen: Die DEL2 hat uns bestätigt, dass während der laufenden Hauptrunde ausschließlich Punkte, danach Tordifferenz und danach erzielte Tore maßgeblich sind. Der direkte Vergleich wird erst für die endgültige Platzierung nach Saisonende herangezogen. Damit sind wir für die laufende Tabelle nicht auf eine von der Datenquelle vorgegebene Reihenfolge angewiesen (siehe DEG und EBR nach dem 1. Spieltag gemeinsam auf Platz 2, in der Tabelle der DEL2 aber willkürlich auf Platz 2 und 3, was eine fehlerhafte Berechnung des delta_rank beim 2. Spieltag zur Folge gehabt hätte).
- Die Änderungen werden zunächst vollständig parallel getestet: Die bestehende produktive Tabelle bleibt unangetastet. Die neue Variante läuft zunächst als „Shadow“ daneben und kann zusätzlich mit den aufgezeichneten Daten der ersten beiden Spieltage noch einmal rückwirkend getestet werden.
Zeitvergleich Datenquelle[2] ↔ Datenquelle[1]
Die Rohdaten wurden dafür noch einmal neu ausgewertet. Verglichen wurde jeweils der erste beobachtete Zeitpunkt derselben echten Spielstandsänderung auf Datenquelle[2] und auf Datenquelle[1]. Der am Freitag zeitweise stark hinterherhängende/„vergessene“ Datensatz von LFX vs. EVL auf Datenquelle[2] wurde komplett herausgenommen, ebenso die bekannten falschen Doppel-Tor-Zwischenstände bei DRE vs. ECK. Der Sonntag zeigt beispielsweise schon bei den ersten DEG-Toren Abstände von deutlich über einer Minute zwischen Datenquelle[2] und Datenquelle[1].
Damit bleiben 86 sauber vergleichbare Spielstandsänderungen aus den ersten beiden Spieltagen. Bei 85 von 86 war Datenquelle[2] schneller. Wenn Datenquelle[2] vorne lag, betrug der kleinste gemessene Vorsprung rund 16 Sekunden, der größte rund 11 Minuten 39 Sekunden, und der durchschnittliche Vorsprung rund 2 Minuten 16 Sekunden. In genau einem der 86 Fälle war dagegen der Datenquelle[1] schneller, und zwar um rund 1 Minute 10 Sekunden. Bezieht man diesen Gegenfall in den Mittelwert mit ein, beträgt der Netto-Zeitvorsprung von Datenquelle[2] immer noch rund 2 Minuten 14 Sekunden pro Spielstandsänderung.
Der Maximalwert von 11:39 stammt dabei vom entscheidenden Shootout-Stand bei EVL vs. DEG. Dieser wurde nicht als Anomalie herausgerechnet: Auch bei den beiden anderen Penaltyschießen war die endgültige Siegerwertung bei Datenquelle[1] auffällig spät. Nimmt man nur zur Einordnung diese drei Shootout-Endstände heraus, liegt der durchschnittliche Netto-Vorsprung aber immer noch bei ungefähr 2 Minuten.
Zuguterletzt werden wir noch das Format der Spieltagsdaten auf JSON umstellen und für jedes Spiel einen eigenen Datensatz führen. Das gibt uns später auch die Möglichkeit, nicht nur eine Tabelle, sondern auch die Live-Ergebnisse aller Spiele eines Spieltags (und rückwirkend der bereits abgeschlossenen Spiele vorheriger Spieltage) anzuzeigen.
Aber das ist erstmal noch Zukunftsmusik, eins nach dem anderen …
P.S.: Wenn hier von "wir" die Rede ist, dann sind damit gemeint der KI-Kollege von ChatGPT und ich. Glaubt ja wohl niemand, dass ich sowas ganz alleine zustande bringen könnte. Trotzdem passiert alles in gemeinsamen Sessions mit entsprechendem Zeitaufwand. Und das Gerüst muss ich zu großen Teilen schon noch selbst bauen und bisweilen auch in die Logik korrigierend eingreifen.