TopLogic - the automated application engine
  • Releases
  • Dokumentation
  • Github
  • Discord
  1. Home
  2. Releases
  3. TL_8.0.0-alpha10
  4. #29696

8.0.0-alpha10
TopLogic Release

2026-10-09

enhancement

major
#29651
TL Views: Container <accordion> mit einklappbaren Abschnitten
#29652
TL Views: Hinweisbox <alert> im Inhalt einer View
#29654
TL Views: Auswahlfeld als Radio-Gruppe für beliebig viele Optionen
#29661
TL Views: Prototyp "TopLogic UI on MUI" – Adaptermodul mit Material UI für die ersetzbaren Komponenten
#29692
TL Views: Formularfelder, Tabellenzellen und das Bearbeiten eines Formulars richten sich nach den Modell-Zugriffsrechten
#29693
TL Views: Große und mehrwertige Werte erscheinen in Tabellenzellen als einzeilige Vorschau mit einem Knopf, der den vollständigen Editor in einem Dialog öffnet
#29707
Reduce PR CI build time: parallel reactor build, sharded scripted tests, affected-module builds
#29730
React-Oberfläche: Kanban-Board als View-Element (Karten per Drag & Drop zwischen Spalten verschieben)
#29735
User menu: the application cannot say what the account is called
#29741
anonymous-Benutzer soll per Default nicht in Personenauswahlfeldern auftauchen
#29744
TL Views: Entwicklerwerkzeuge (Designer, Aufzeichnen, Untersuchen, Agentenzugriff) in einem eigenen Entwicklungsmenü der App-Leiste
#29752
React-UI: Kleine Verbesserungen der Oberfläche (Snackbar, Hover, Tooltips, Schieberegler, Abstände)
#29758
ModelAccessRights: Anlegerecht in Kompositionsattribut für Spezialisierung des Zieltyps prüfen
#29759
React-UI: Commit-Nachrichten für Änderungen aus Sichten (TL-Script-Aktionen, Transaktionen, Löschen) konfigurierbar, sinnvolle Standard-Nachrichten
#29760
Improve the React UI of the model-based security configuration; let a TL-Script function determine the access parent of a type
#29765
Engine developer docs (FAQ) are not discoverable when developing an application based on the engine
minor
#29513
Drag&Drop: Commit-Nachricht für Drop-Operationen konfigurierbar, sinnvolle Standard-Nachricht
#29747
Make the LDAP configuration ldapConf.xml configurable by system properties / environment variables
#29754
OpenAPI-Server: Variablenname für Request-Parameter, deren Name kein gültiger TL-Script-Bezeichner ist (z.B. Header X-Gitea-Event)

defect

major
#29581
TopLogicServlet: Vertrag dokumentieren - eine Anfrage hat nur im Fenster einen Benutzer
#29642
React dialog size memory: one key for every dialog, stored size beats the declared width and is never clamped to the window
#29646
TL Views: Der Build der React-Client-Module prüft die TypeScript-Typen nicht, in com.top_logic.layout.react sind dadurch 29 Typfehler aufgelaufen
#29697
HistoryQuery: Start- und Stop-Revision aus HistoryQueryArguments werden bei der Suche ignoriert.
#29701
TL Views: a form shown again after its sidebar section or tab was hidden keeps the values it had when hidden; a reload renders the stale values again
#29711
Setzen einer geordneten Liste (ListStorage) ist beim Einfügen vor bestehenden Elementen überquadratisch langsam; TestListStorage misst Wanduhrzeit und scheitert unter Last
#29712
Problem beim Zurücksetzen einer Selektion im Baum
#29716
Modellbasierte Leseprüfung: Rollen-Lookup kompiliert pro Objekt und Gruppe neue KB-Abfragen, Nicht-Admin wartet 70 s statt 9 s
#29723
Model editor class diagram fails with "Comparison method violates its general contract!"
#29724
PathNavigation: abstract attribute rejected by isDerived() check even though concrete overrides exist and are tracked
#29728
FlowChartComponent: Ein Neubau des Diagramms entfernt Objekte aus der Selektion, die im Diagramm nicht dargestellt werden
#29731
TL Views: <persist-transient> copies the draft's empty values over the creation defaults; a sequence number or creation date computed at commit is lost
#29732
TL Views: <create-transient container="…"> creates the draft without the container's context; option lists and context-dependent defaults of the draft see no container
#29734
View form: <store-form-state/> does not persist new rows of a <composition-table>, so saving a persistent owner fails
#29737
TL Views: a collapsing toolbar measures its commands only when its groups change; a command that shows itself later keeps a 0 px toolbar and draws over the panel title
#29740
Fehlender Schutz für den anonymous-Benutzer
#29745
Zugriff auf ein abstraktes Attribut meldet einen Fehler, der nicht sagt, dass das Attribut abstrakt ist: eigene Storage für abstrakte Attribute
#29746
FileManagerOverlay/FileManagerDelegate cannot read resources inside web-fragment WARs (tl_config overlay fails on engine configuration files)
#29773
PostgreSQL: Große SQL-Migrationen werden durch nicht freigegebene Autosave-Savepoints quadratisch langsam
minor
#29029
Incrementally deactivated drop-down select box can still be operated
#29514
Befehlsfreigabe und Berechtigung von Drag&Drop
#29696
Scheduler: Start- und Cluster-Verhalten von Tasks bereinigen – <on-startup/> pro Knotenstart, Tasks erst ab RUNNING, run-on-startup entfernen, kein Default für isNodeLocal()
#29699
TL-Script: htmlText(htmlSource($text), images) drops the images of a stored structured text, since it does not accept the "ref:" references it writes itself
#29700
TL Views: the open session of a deleted account keeps evaluating as that account; every model event logs "DeletedObjectAccess … was already deleted" from its observers
#29722
FlowDiagram: Fehlerhafte Baum-Layout-Berechnung
#29727
TL-Script Auswertungen mit Filtern können zu "null"-Literalen führen.
#29733
TL Views: a click on the padding of the React rich-text editor's content area does not focus the editor; the typed text is lost
#29736
Click-region menu opens flush on the window edge and under the trigger's tooltip
#29738
TL Views: the menu cliques of a toolbar are labelled in English in every language ("More", "View", "Export")
#29739
React tooltip stays open at the window's top-left corner when its anchor is removed under the pointer
#29743
React UI: Tooltip eines Menüeintrags erscheint hinter dem Menü
#29753
OpenAPI-Client: NullPointerException bei Antwort ohne Body (z.B. 204) mit Status ungleich 200
#29774
OpenAPI server: API key authentication cannot resolve an account — Person.byName called without an InteractionContext

task

major
#29725
CheckDependencies: npm-Abhängigkeiten werden nicht aktualisiert, transitive Maven-Abhängigkeiten mit bekannten Sicherheitslücken
#29726
WYSIWYG-Editor: Umstellung auf Tiptap 3 (Sicherheitslücke GHSA-cp6q-959q-f8rh)
defect

minor

#29696

Scheduler: Start- und Cluster-Verhalten von Tasks bereinigen – <on-startup/> pro Knotenstart, Tasks erst ab RUNNING, run-on-startup entfernen, kein Default für isNodeLocal()

MigrationScheduler

Problem

1. `<on-startup/>` funktioniert bei clusterweiten Tasks nicht

Der Schedule <on-startup/> (com.top_logic.util.sched.task.schedule.OnStartup) soll einen Task nach dem Start der Anwendung ausführen. Bei Tasks, die nicht pro Knoten laufen (Task#isNodeLocal() = false, damit Task#isPersistent() = true), löst er nur beim allerersten Start der Anwendung aus, also nach der Installation. Bei allen weiteren Starts wird der Lauf übersprungen.

Betroffen ist u.a. der RefreshUsersTask aus der Engine-Konfiguration (top-logic.config.xml), der <on-startup/> mit <periodically> kombiniert und isNodeLocal() = false liefert. Ebenso betroffen sind alle ScriptTask`s und `CompositeTask`s, die `<on-startup/> verwenden.

Ursache (aus dem Code abgeleitet):

  • OnStartup.nextSchedule(notBefore, lastSchedule) liefert nur dann einen Termin, wenn lastSchedule == NO_SCHEDULE ist, also noch kein Lauf bekannt ist.
  • TaskImpl.lastSched beginnt in jeder JVM bei NO_SCHEDULE. Bei knotenlokalen Tasks löst OnStartup deshalb bei jedem Start aus.
  • Bei clusterweiten Tasks ruft Scheduler.tryStartTaskUnsafe() vor dem Start requestClusterLock() auf, und dieses ruft runRecently() auf. runRecently() liest das letzte persistierte Ergebnis (TaskLogWrapper.getCurrentResult() = das neueste TaskResult, auch aus einem früheren Start) und übernimmt dessen Startzeit per markAsRun(lastRun) als lastSched. Danach liefert OnStartup NO_SCHEDULE. runRecently() meldet true, und der Task wird als „is or recently was running on an other cluster node“ übersprungen.

OnStartup interpretiert „Start“ also als „kein Lauf bekannt“ statt als „kein Lauf seit dem Start“.

2. Die Task-Option `run-on-startup` ist missverständlich und überflüssig

run-on-startup (TaskImpl.Config#isRunOnStartup(), Task#isRunOnStartup(), Default true) liest sich so, als würde ein Task mit true beim Start immer ausgeführt. Tatsächlich gilt:

  • TaskImpl.attachTo(Scheduler) ruft setRunOnStartup(_runOnStartup) auf. Bei true passiert nichts. Bei false wird lastSched = now gesetzt, wenn der nächste Termin nicht in der Zukunft liegt.
  • Beim Start werden die Termine ab notBefore = now berechnet, ohne dass ein letzter Lauf bekannt ist. Die periodischen Schedules (DailySchedule, WeeklySchedule, MonthlySchedule, DailyPeriodicallySchedule) und OnceSchedule liefern dabei nie einen Termin in der Vergangenheit. Ein während der Downtime verpasster Termin wird also ohnehin nie nachgeholt.
  • Wirkung hat false deshalb nur auf sofort fällige Schedules: <on-startup/> wird vollständig unterdrückt, ein noch nie ausgeführtes LegacyDateSchedule mit vergangenem Datum ebenfalls. Bei AlwaysSchedule hat es praktisch keine Wirkung.
  • Die Option bedeutet also im Kern „ignoriere <on-startup/>“ und widerspricht damit einer explizit konfigurierten Schedule. Ein Task, der beim Start nicht laufen soll, bekommt einfach kein <on-startup/>.
  • Die Begründung in CompactHistoryTask.Config#isRunOnStartup() (ein verpasster Termin dürfe die Komprimierung beim Start nicht auslösen) beschreibt einen Fall, den es nicht gibt.

In der Engine-Konfiguration kombiniert kein Task run-on-startup="false" mit einem sofort fälligen Schedule. Alle vorhandenen Angaben der Option sind dort wirkungslos (CheckUnusedAccountsTask, TranslationServiceResetTask mit <daily>; RefreshUsersTask, SchedulerClusterCleanupTask, BPETimeoutTask mit true).

3. Tasks können während des Systemstarts laufen

Alle Dienste, auch der Scheduler, werden in AbstractStartStopListener.startupModuleSystem() innerhalb einer einzigen Start-Transaktion gestartet. Danach folgen MigrationService.applicationStarted(), der Commit, initApplication() und erst dann der Knotenzustand NodeState.RUNNING (im Cluster zusammen mit der Freigabe des Start-Tokens). Ein Task, der in dieser Phase läuft, sieht den noch nicht committeten Startzustand nicht, und später gestartete Dienste sind noch nicht verfügbar.

Dagegen schützt bisher nur die Scheduler-Option dont-run-tasks-on-startup (SchedulerConfig#isDontRunTasksOnStartup()): Mit true fragt Scheduler.dispatchWithThreadContext() den Knotenzustand im Abstand von startup-sleep ab, bis RUNNING erreicht ist. Die Engine-Konfiguration setzt true, der Default der Option ist aber false. Für einen Lauf während des Starts gibt es keinen Anwendungsfall.

4. Clusterweite Tasks laufen per Default auf jedem Knoten

TaskImpl#isNodeLocal() liefert fest true; TaskImpl#isPersistent() ist !isNodeLocal(). Nur RefreshUsersTask, ScriptTask (fest false) und CompositeTaskImpl (aus den Kindern abgeleitet) überschreiben das. Jeder andere Task läuft im Cluster auf jedem Knoten, auch solche, die die Datenbank verändern und damit mehrfach bzw. gleichzeitig auf mehreren Knoten arbeiten, z.B. CheckUnusedAccountsTask (benachrichtigt und löscht Accounts), CompactHistoryTask, GenericDataImportTask, GenericTwoPhaseImportTask, AutomaticDataImportTask, DataObjectImportTask, ExcelSupplierImportTask. Nur Unterklassen von TokenBasedTask (AbstractMailServerDaemon) und KBDataProducerTask schützen sich selbst über eine Datenbank-Sperre.

Der Default verdeckt, dass die Entscheidung „auf jedem Knoten“ vs. „einmal im Cluster“ eine Eigenschaft dessen ist, was der Task tut. Beim ScriptTask ist dieses „was“ konfiguriert, die Entscheidung aber fest codiert (false), sodass ein Script, das z.B. einen knotenlokalen Cache zurücksetzt, nicht korrekt konfigurierbar ist.

5. Ein Cluster-Lock aus einem früheren Start desselben Knotens bleibt stehen

Endet ein Start eines Knotens, während ein clusterweiter Task läuft (Absturz, Abbruch), bleibt dessen Cluster-Lock im Task-Log stehen. Beim nächsten Start desselben Knotens gibt TaskLogWrapper.startupNodeCleanGlobal() den Lock nur frei, wenn Knotenname und Knoten-ID übereinstimmen. Die Knoten-ID ändert sich aber bei jedem Start, sodass der Lock nie freigegeben wird: Es wird „Cluster lock values are out of sync“ als ERROR protokolliert, und der Task bleibt gesperrt, bis der (per Default deaktivierte) SchedulerClusterCleanupTask den Lock entfernt.

Umsetzung

Tasks laufen erst, wenn alle Dienste gestartet sind

  • Der Scheduler-Dienst startet seinen Dispatch-Thread nicht in seinem startUp(), sondern erst, wenn das Modulsystem läuft. Es gibt kein Warten per Polling mehr.
  • Dafür meldet com.top_logic.basic.module.ModuleUtil allgemein, wann das Modulsystem läuft (ModuleUtil#isRunning()): Eine Anwendung hat ihre Dienste gestartet (startApplicationServices(Collection), beim Anwendungsstart über startConfiguredModules()), alle diese Dienste sind aktiv, und es ist keine Startphase (ModuleUtil.StartupPhase) offen. Jede Operation von ModuleUtil, die Dienste startet oder neu startet (startUp, restart, …), läuft in einer eigenen Startphase; Phasen sind geschachtelt. Ein Dienst, der vorher nicht aktiv werden darf, registriert eine Aktion mit whenRunning(Runnable). Sie läuft, sobald die äußerste Startphase endet und das Modulsystem läuft, bzw. sofort, wenn es bereits läuft.
  • AbstractStartStopListener.boot() klammert den gesamten Anwendungsstart bis einschließlich NodeState.RUNNING in eine Startphase. Tasks laufen also erst nach dem Commit der Start-Transaktion und nach initApplication().
  • Ein Neustart von Diensten (ein einzelner Dienst oder alle Dienste, z.B. durch einen Neustart von XMLProperties in Test-Setups) ist eine Startphase: Der neu gestartete Scheduler beginnt erst, wenn alle neu gestarteten Dienste wieder laufen.
  • Ohne Anwendungsstart (Tests, Werkzeuge, die einzelne Dienste starten) gibt es keine Anwendungsdienste, und der Scheduler führt keine Tasks aus – wie bisher mit dont-run-tasks-on-startup="true". Tests, die die Ausführung durch den Scheduler brauchen, nutzen das Test-Setup test.com.top_logic.basic.module.RunningModuleSystemSetup, das die bei seinem Setup aktiven Dienste als Anwendungsdienste erklärt (genutzt von TestingScheduler.wrapSchedulerDependenciesSetup() und TestSchedulerOnStartup).
  • Die Scheduler-Optionen dont-run-tasks-on-startup und startup-sleep entfallen, ebenso ihre Angaben in top-logic.config.xml und top-logic.test.config.xml.
  • Scheduler#getDispatchStart() liefert den Zeitpunkt, zu dem der Scheduler mit dem Ausführen von Tasks begonnen hat.

`<on-startup/>`: ein Lauf pro Start des Schedulers

  • OnStartup löst aus, wenn noch kein Lauf bekannt ist oder der letzte Lauf vor Scheduler#getDispatchStart() begonnen hat. Dann ist es unerheblich, ob lastSchedule aus der Laufzeit oder aus dem persistierten Task-Log stammt.
  • Jeder Start eines Knotens (und jeder Neustart des Scheduler-Dienstes) löst damit einen Lauf aus, auch bei clusterweiten Tasks und auch wenn andere Knoten bereits laufen. Über den Cluster-Lock läuft ein clusterweiter Task dabei weiterhin nur auf einem Knoten gleichzeitig. Hat ein anderer Knoten den Task nach dem Start dieses Knotens bereits ausgeführt, zählt dieser Lauf, denn bei einem clusterweiten Task ist unerheblich, welcher Knoten ihn ausführt.
  • Bewusst nicht „einmal pro Cluster-Start“: Das ließe sich nur über die Lebenszeichen der Knoten erkennen und würde nach einem Absturz innerhalb des Knoten-Timeouts sowie bei rollierenden Deployments nie auslösen.

Cluster-Lock eines früheren Starts freigeben

  • Beim Start gibt TaskLogWrapper.startupNodeCleanGlobal() einen Cluster-Lock frei, der auf den Namen dieses Knotens lautet, unabhängig von der gespeicherten Knoten-ID (neue Methode TaskLogWrapper#isClusterLockOfThisNode()). Der Knotenname ist im Cluster eindeutig und bleibt über Neustarts gleich; da der Knoten zu diesem Zeitpunkt noch keine Tasks ausführt, kann ein solcher Lock nur aus einem früheren Start stammen. Der Task wird als inaktiv markiert, offene Ergebnisse als ERROR („Task war beim Herunterfahren aktiv“).
  • Ein Lock eines anderen Knotens bleibt unverändert.

`run-on-startup` entfernen

  • TaskImpl.Config#isRunOnStartup(), Task#isRunOnStartup(), TaskImpl#setRunOnStartup(boolean) sowie die Auswertung in TaskImpl.attachTo(Scheduler) entfernt, ebenso die Legacy-Property runOnStartup im Properties-Konstruktor von TaskImpl.
  • CompactHistoryTask.Config#isRunOnStartup(), TaskWrapper#isRunOnStartup() und die Aufrufe von setRunOnStartup(false) in EnterMaintenanceWindowTask, AutomaticDataImportTask, SAPPersonImporter und SAPSupplierImporter entfernt.
  • Scheduler-Administration: Spalte runOnStartup (scheduler.xml), TaskAccessor.RUN_ON_STARTUP, das Feld in EditTaskComponent/`EditTask.jsp` sowie die Ressourcen admin.sys.scheduler.runOnStartup und admin.sys.scheduler.task.runOnStartup entfernt.
  • TriggerTask.jsp (manuelles Anstoßen eines Tasks) nutzte setRunOnStartup(false), um den letzten Lauf auf „jetzt“ zu setzen; es ruft dafür jetzt Task#markAsRun(long) auf.
  • Das Attribut run-on-startup in top-logic.config.xml und tl-bpe.conf.config.xml entfernt.

Kein Default für `isNodeLocal()`

  • TaskImpl ist abstrakt und implementiert isNodeLocal() nicht mehr. Jede Task-Implementierung entscheidet selbst, ob sie auf jedem Knoten oder einmal im Cluster läuft. Die JavaDoc von Task#isNodeLocal() und Task#isPersistent() beschreibt beide Varianten, die Pflichten eines persistenten Tasks (eigener ThreadContext, Ergebnisprotokoll mit taskStarted/`taskEnded` pro Lauf) und eine Faustregel für die Entscheidung.
  • Neue Methode TaskImpl#runWithResultProtocol(Runnable): führt die Arbeit in einem System-ThreadContext aus und schreibt das Ergebnisprotokoll (CANCELED/WARNING/SUCCESS/ERROR), sofern die Arbeit es nicht selbst beendet. StateHandlingTask nutzt sie.
  • ScriptTask bekommt die Option node-local (Default false, einmal im Cluster).
  • CompositeTaskImpl bleibt bei der Ableitung aus seinen Kindern.
  • Die Legacy-Fabrikmethoden in TaskWrapper erzeugen eine private konkrete Unterklasse (knotenlokal wie bisher). Die Tests nutzen die Testklasse TestingTask.
Einordnung der Engine-Tasks

Einmal im Cluster (false) – verändern persistente Daten oder wirken nach außen:

  • CheckUnusedAccountsTask, CompactHistoryTask, GenericDataImportTask, GenericTwoPhaseImportTask, AutomaticDataImportTask, DataObjectImportTask (mit allen Importer-Unterklassen), ExcelSupplierImportTask, RefreshUsersTask (unverändert).
  • EnterMaintenanceWindowTask: Der Wartungsmodus ist clusterweit. MaintenanceWindowManager.enterMaintenanceWindow(long, boolean) setzt die Cluster-Properties PROPERTY_ALLOW_LOGIN und PROPERTY_STATE_CHANGE über den ClusterManager. Liefe der Task auf jedem Knoten, würde jeder Knoten den Wartungsmodus erneut ankündigen und den Endzeitpunkt überschreiben.
  • Die bisher knotenlokalen Tasks unter diesen schrieben großteils kein Ergebnisprotokoll bzw. liefen ohne ThreadContext (CheckUnusedAccountsTask, GenericDataImportTask, GenericTwoPhaseImportTask, ExcelSupplierImportTask, EnterMaintenanceWindowTask, AutomaticDataImportTask). Als persistente Tasks brauchen sie es, da der Scheduler sonst jeden Lauf als abgebrochen meldet und einen Lauf auf einem anderen Knoten nicht erkennt. Sie nutzen jetzt runWithResultProtocol bzw. einen eigenen System-Kontext; ein Fehler erscheint damit als ERROR-Ergebnis statt nur im Log. DataObjectImportTask schließt den Lauf auch dann ab, wenn kein Mandant importiert wurde.

Auf jedem Knoten (true):

  • BPETimeoutTask: läuft alle paar Sekunden; ein Cluster-Lock kostete pro Lauf mehrere Commits (Lock setzen, Start, Ende, Lock freigeben), d.h. zehntausende Revisionen pro Tag. Gleichzeitige Läufe auf mehreren Knoten bearbeiten dieselben Prozessdaten, sodass der Commit aller Läufe bis auf einen mit einem Konflikt scheitert. Der Task läuft jetzt in einem System-ThreadContext über runWithResultProtocol (transientes Ergebnisprotokoll).
  • TranslationServiceResetTask: setzt einen knotenlokalen Cache zurück.
  • CleanUpTask (mit CleanImageTmpTask, CleanSysTmpTask): räumt das lokale Temp-Verzeichnis auf.
  • SchedulerClusterCleanupTask: gibt die Cluster-Locks von Task-Logs frei, deren Knoten tot ist. Als clusterweiter Task hätte er selbst einen Cluster-Lock; stirbt der Knoten, der ihn gerade ausführt, bliebe dieser Lock stehen, und kein anderer Knoten könnte ihn mehr starten. Die Implementierung setzt die Ausführung auf jedem Knoten auch voraus (zufälliger Backoff in checkClusterStateRetrying()).
  • KBDataProducerTask: koordiniert die Knoten selbst über einen Compare-and-Set-Lock auf der zuletzt gesendeten Revision.
  • TokenBasedTask (AbstractMailServerDaemon): schützt sich über seine eigene Datenbank-Sperre.

Migration

Die Task-Option run-on-startup sowie die Scheduler-Optionen dont-run-tasks-on-startup und startup-sleep entfallen. Eine Konfiguration, die eine davon noch setzt, wird beim Start als fehlerhaft abgelehnt.

  • In allen Konfigurationsdateien (*.config.xml) das Attribut run-on-startup an <task>-Elementen entfernen. Mit run-on-startup="true" ändert sich dadurch nichts.
  • Hatte ein Task run-on-startup="false" und in seinen <schedules> ein <on-startup/>, lief er bisher beim Start nicht. Um dieses Verhalten zu erhalten, das <on-startup/> entfernen. Mit anderen Schedules war run-on-startup="false" wirkungslos und kann ersatzlos entfallen.
  • Die Attribute dont-run-tasks-on-startup und startup-sleep an der Konfiguration des Service com.top_logic.util.sched.Scheduler entfernen. Tasks starten jetzt immer erst, wenn die Anwendung vollständig hochgefahren ist. Das entspricht dem bisherigen Verhalten mit dont-run-tasks-on-startup="true".
  • Tests, die Dienste ohne Anwendungsstart hochfahren und die Ausführung von Tasks durch den Scheduler brauchen, müssen in das Test-Setup test.com.top_logic.basic.module.RunningModuleSystemSetup eingebettet werden.
  • Eigene Task-Implementierungen, die setRunOnStartup(...) aufrufen oder isRunOnStartup() überschreiben, müssen diese Aufrufe bzw. Überschreibungen entfernen.
  • Eigene Task-Implementierungen, die direkt oder indirekt von TaskImpl erben und isNodeLocal() nicht überschreiben, kompilieren nicht mehr. Sie müssen isNodeLocal() implementieren: true, wenn der Task auf jedem Cluster-Knoten laufen muss (bisheriges Verhalten), false, wenn er nur einmal im Cluster laufen darf. Mit false gelten die Pflichten aus Task#isPersistent() (eigener ThreadContext, Ergebnisprotokoll pro Lauf); am einfachsten erbt der Task von StateHandlingTask oder ruft in run() runWithResultProtocol(...) auf. In einem Cluster ist false für jeden Task zu prüfen, der persistente Daten verändert.
  • Direkte Instanziierungen von TaskImpl (new TaskImpl(...)) müssen durch eine konkrete Unterklasse ersetzt werden.
  • Engine-Tasks, die bisher auf jedem Knoten liefen und jetzt einmal im Cluster laufen (siehe Einordnung der Engine-Tasks), erscheinen in der Scheduler-Administration als persistent mit Cluster-Lock und Ergebnisprotokoll.
  • Ein ScriptTask, dessen Script nur knotenlokal wirkt (z.B. einen lokalen Cache zurücksetzt), kann mit node-local="true" auf jedem Knoten ausgeführt werden.
  • Ein clusterweiter Task mit <on-startup/> läuft jetzt bei jedem Start eines Knotens, bisher nur beim ersten Start nach der Installation.
  • Get Started
  • Github
  • Discord
  • Das Unternehmen hinter TopLogic
  • Softwareentwicklung heute
  • Kontakt

© Copyright – Business Operation Systems GmbH

  • top-logic.com
  • Nutzungsbedingungen
  • Impressum
  • Rechtlicher Hinweis
  • Datenschutz
  • DE
  • Login