HCL Notes / Domino / Diverses > Administration & Userprobleme
JavaAgent bringt eine Instanz vom AgentManager zum Absturz, Out of Memory
mapbug:
Guten Tag,
Ich habe ein Problem mit meinem JavaAgent auf dem Domino.
Zuerst versorge ich euch mit ein paar Infos:
- ursprüngliches Problem warum der Agent entstanden ist:
Ich habe eine XPage erstellt mit klassischen Portaldaten pro Benutzer und Datum (Aufträge, Angebote, Verkaufsaktivitäten, Umsätze, ....)
Diese XPage läuft nicht nur im Browser sondern auch im Notes Client selbst. Dazu waren wegen des veralteten Java Script Standards
viele manuelle Anpassungen notwendig. Dort verwende ich auch JavaScript Frameworks wie charts.js und Jquery DataTables.
Die Daten holte ich via Domino RESTServices (JavaScript).
Ausszug XPage
https://ibb.co/VVhX79J
Das Problem dabei war, dass bei manchen Benutzern, die eben mehr Daten durch ihre Berechtigung sehen durften, diese Seite länger als eine Minute brauchte dass alle Daten
geladen waren. Dieses Problem habe ich monatelang in Verbindung mit der HCL und kompetenten Partnerfirmen analysiert.
Ich habe viele, viele Ideen und Einstellungen probiert und wir sind zum Schluss gekommen, dass es wohl besser wäre diese Daten nächtlich zu berechnen und abzuspeichern
da die Performance (vorallem das Durchschleifen der Dokumente) echt mies ist.
In der XPage hole ich dann je nach Auswahl des Benutzers und Datums das korrekte Dokument und die Seite ist in weniger als 4 Sekunden komplett geladen.
(Wenn jemand mehr dazu wissen will -> PN)
- Was macht der Agent?
Der Agent läuft viele Ansichten von mehreren Domino Dbs durch und holt sich daraus Informationen.
Diese Informationen werden als JSON in einem Dokument abgespeichert.
Codeauszug
--- Code: ---// Dokument erstellen
portalxsp = dbPortal.createDocument();
....
JSONObject angebote = getAngebote(benutzer, datum, waehrung);
// JSON Daten in Richtextfeld speichern
if (portalxsp.hasItem("angebote")) {
portalxsp.removeItem("angebote");
}
rtItem = (RichTextItem) portalxsp.createRichTextItem("angebote");
rtItem.appendText(angebote.toString());
rtItem.update();
rtItem.recycle();
... (weitere Methoden) ...
portalxsp.save(true, false);
portalxsp.recycle();
private JSONObject getAngebote(Document docbenutzer, Calendar datum, String waehrung) {
List<JSONObject> angebote = new ArrayList<JSONObject>();
try {
Date date = datum.getTime();
// mit Berechtigungen von ausgewählten Benutzer filtern
StringBuilder suchString = new StringBuilder();
suchString.append(berechtigungsMap.get(docbenutzer.getItemValueString("Benutzer")));
String kd = "KD";
suchString.append(" AND Field Angebotsdatum = " + dfddMyyyy.format(date));
// keine Kundendienstaufträge anzeigen
suchString.append(" AND NOT (Field ProduktGruppe = \"" + kd + "\")");
viewAngeboteXSP.FTSearch(suchString.toString());
ViewEntryCollection col = viewAngeboteXSP.getAllEntries();
ViewEntry ve = col.getFirstEntry();
while (ve != null) {
JSONObject angebot = new JSONObject();
Vector colVals = ve.getColumnValues();
angebot.put("Kundenname", colVals.get(11).toString().trim());
angebot.put("Angebot", colVals.get(3));
angebot.put("DoklinkAngebot", colVals.get(8));
angebot.put("Produktgruppe", colVals.get(10).toString().trim());
BigDecimal betrag = BigDecimal.ZERO;
Object betragObj = colVals.get(7);
if (betragObj instanceof Double) {
betrag = new BigDecimal((Double) betragObj).setScale(2, BigDecimal.ROUND_HALF_UP);
} else {
betrag = BigDecimal.ZERO;
}
angebot.put("Wert", umwandelnBetrag("EUR", waehrung, betrag, date));
// aktuelle Daten zu Array hinzufügen
angebote.add(angebot);
// nächsten Eintrag lesen
ViewEntry tmpve = ve;
ve = col.getNextEntry();
tmpve.recycle();
}
col.recycle();
int len = angebote.size();
if (len > 1) {
// Sortieren nach KdNr, Angebot
angebote.sort(new ComparatorAngebot());
}
JSONObject jsonResult = new JSONObject();
jsonResult.put("data", angebote);
return jsonResult;
} catch (Exception e) {
try {
System.err.println("Fehler in getAngebote bei Benutzer " + docbenutzer.getItemValueString("Benutzer"));
} catch (NotesException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
return null;
}
--- Ende Code ---
Ich werde hier nicht den kompletten Code posten da das Programm über 4000 Zeilen Code hat und die jeweiligen Methoden immer gleich aufgebaut sind.
- Wie habe ich den JavaAgenten am Domino erstellt?
Neuer Java-Agent. Innerhalb der NotesMain() Methode, meine gewünschte Methode aufgerufen.
Die .jar Dateien binde ich als Archivdateien beim JavaAgenten ein.
--- Code: ---public void NotesMain() {
....
try {
// Portale Erstellen
String[] args = null;
Portal.main(args);
// Dump Thread Group
Portal.dumptg(null);
} catch(Exception e) {
e.printStackTrace();
}
}
--- Ende Code ---
Ich habe gelesen dass man die .jar Files besser in ..jvm\lib\ext einbinden soll.
Das habe ich zwecks Sicherheitsbedenken nicht gemacht da diese .jars dort alle Rechte haben.
Laut Bug SPR # BHUY8PRMKK werden die .jar Dateien bei jedem Start des Agenten in den Speicher geladen und bleiben dort.
Als Alternative habe ich eine Lösung von eknori gefunden -> EnableJavaAgentCache=2 in der notes.ini.
Mit diesem Parameter werden die .jars wiederverwendet und nicht immer neu in den Speicher geladen
https://www.eknori.de/2021-03-20/java-agents-with-imported-jar-files/
-> Der Agent wird jede Nacht ausgeführt.
- Probleme?
1) Der Agent kann nach dem Durchlauf ab und zu nicht alle Threads bereinigen und liefert: Java Agent "Error cleaning up agent threads"
Die Threads lasse ich laut https://support.hcltechsw.com/csm?id=kb_article&sysparm_article=KB0032652 ausgeben.
--- Code: --- Agent Manager: Agent printing: ThreadGroup UTG: JavaAgent, objid = 1751964594
Agent Manager: Agent printing: subgroups = 0
Agent Manager: Agent printing: total threads = 2
Agent Manager: Agent printing: Thread Name, ThreadID, ThreadGroup
Agent Manager: Agent printing: AS400 Read Daemon [system:ATARTW01;job:515458/QUSER/QZDASOINIT], -663952502, UTG: JavaAgent
Agent Manager: Agent printing: AgentThread: JavaAgent, 1991637412, UTG: JavaAgent
--- Ende Code ---
Da sehe ich nur einen Java Agenten und einen Verbindungsjob der Daten aus unserer IBM i abgreift.
Ich verstehe nicht warum er diese Threads nicht komplett bereinigen kann nachdem der Agent durchgelaufen ist.
2) Der Agent bricht ab und zu mit der Fehlermeldung: LSXBE: Out Of Backend Memory ab.
Dies lässt eine Instanz vom Agent Manager abstürzen.
--- Code: --- LSXBE: ************************************
LSXBE: ****** Out of Backend Memory *******
LSXBE: ************************************
Agent Manager: Agent error: Fehler in getVorschlaegeTelefonateA bei Benutzer CN=XXXXXX XXXXX/O=Artweger/C=AT
Agent Manager: Agent error: NotesException: Out of Memory
Agent Manager: Agent error: at lotus.domino.local.DocumentCollection.NgetNextDocument(Native Method)
Agent Manager: Agent error: at lotus.domino.local.DocumentCollection.getNextDocument(Unknown Source)
Agent Manager: Agent error: at artweger.programs.crm.portal.Portal.getVorschlaegeTelefonateA(Portal.java:2789)
Agent Manager: Agent error: at artweger.programs.crm.portal.Portal.erstelleXSPPortalDokument(Portal.java:562)
Agent Manager: Agent error: at artweger.programs.crm.portal.Portal.erstellePortalSeiten(Portal.java:427)
Agent Manager: Agent error: at artweger.programs.crm.portal.Portal.main(Portal.java:83)
Agent Manager: Agent error: at JavaAgent.NotesMain(Unknown Source)
Agent Manager: Agent error: at lotus.domino.AgentBase.runNotes(Unknown Source)
Agent Manager: Agent error: at lotus.domino.NotesThread.run(Unknown Source)
PANIC: CheckTheProcesses - Prozess C:\Program Files\HCL\Domino\nAMgr.EXE (5744/0x1670) untergeordnetes Element von 1272/0x4F8 wurde aufgrund eines Fehlers beendet.
--- Ende Code ---
Dies passiert allerdings nicht jeden Tag.
Auch hierzu habe ich bereits lange das Internet bemüht und das einzige was ich gefunden habe, ist, dass man alle Domino Objekte recyclen soll.
Dies habe ich natürlich gemacht und mehrfach! kontrolliert. (bzw. kontrollieren lassen)
Was mir hier aufällt ist, dass der Fehler immer kommt wenn der Agent gerade Ansichten oder Dokumente durchläuft.
Kann es sein dass er recycelte() Dokumente doch irgendwie im Speicher behält? Oder das recyceln() länger dauert?
Natürlich laufen noch weitere Dinge am Domino, jedoch gab es vor dem Agenten nicht dieses Problem.
Egal welche Methode. Letztes Mal war es eben diese.
Das nsd.log spuckt folgendes aus:
--- Code: ---############################################################
### thread 2/131: [ nserver: 04f8: 13a8]
############################################################
[ 1] 0x7FF874F55D14 ntdll.ZwWaitForSingleObject+20 (0,7FF84EE114B6,21E32D2ED14,3ED044EE18F0D)
[ 2] 0x7FF8715C6D1F KERNELBASE.WaitForSingleObjectEx+143 (0,3FF00000000,0,608)
@[ 3] 0x7FF84EE13E89 nnotes.WaitOnNativeSemaphore+153 (ffffffff,7FF851921C28,0,0)
@[ 4] 0x7FF84EE12345 nnotes.OSWaitEvent+149 (21E30C0858C,3e8,0,3e8)
@[ 5] 0x7FF84F611414 nnotes.MQGetExtended+436 (3C00011648,3CC1DBF5C0,310,0)
@[ 6] 0x7FF84F6111E2 nnotes.MQGet+50 (0,21E2F830000,0,0)
@[ 7] 0x7FF84F5DD66D nnotes.fileWriterT+125 (21E32B30000,0,0,0)
@[ 8] 0x7FF84EDEF688 nnotes.ThreadWrapper+264 (0,0,0,0)
[ 9] 0x7FF8735B84D4 KERNEL32.BaseThreadInitThunk+20 (0,0,0,0)
[10] 0x7FF874F01791 ntdll.RtlUserThreadStart+33 (0,0,0,0)
....
############################################################
### thread 120/131: [ nserver: 04f8: 0f44] FATAL THREAD (Panic)
############################################################
[ 1] 0x7FF874F55D14 ntdll.ZwWaitForSingleObject+20 (68736100000010,0,0,3CC95F90E0)
[ 2] 0x7FF8715C6D1F KERNELBASE.WaitForSingleObjectEx+143 (10,FFFFFFFFFFFFFFF,7FF800000000,257c)
@[ 3] 0x7FF84EDDCAEA nnotes.OSRunExternalScript+1546 (5,0,179c,0)
@[ 4] 0x7FF84EDD917C nnotes.FRTerminateWindowsResources+1532 (5,0,0,1)
@[ 5] 0x7FF84EDDAB63 nnotes.OSFaultCleanupExt+1395 (0,5670,0,3CC95FD8A0)
@[ 6] 0x7FF84EDDA5E7 nnotes.OSFaultCleanup+23 (5670,0,0,0)
@[ 7] 0x7FF84EE47856 nnotes.OSNTUnhandledExceptionFilter+390 (3CC95FA820,7FF8503F62D8,3CC95FD8A0,FFFFE1E99563353)
@[ 8] 0x7FF84EDDD77A nnotes.Panic+1066 (1670,1258A4D003604C9,9,4f8)
@[ 9] 0x7FF8691023BD nserverl.CheckTheProcesses+461 (800207ea,3C00000055,1670,2)
@[10] 0x7FF8691047E0 nserverl.ProcessMonitorTask+368 (88,0,7FF8731B0000,0)
@[11] 0x7FF869101A78 nserverl.Scheduler+888 (0,0,d215005c,21E38C58BF0)
@[12] 0x7FF84EDEF688 nnotes.ThreadWrapper+264 (0,0,0,0)
[13] 0x7FF8735B84D4 KERNEL32.BaseThreadInitThunk+20 (0,0,0,0)
[14] 0x7FF874F01791 ntdll.RtlUserThreadStart+33 (0,0,0,0)
--- Ende Code ---
- Info:
Der Agent läuft ohne Probleme auf Windows PC bzw Windows Server durch.
Von daher habe ich eine funktionierende Alternative. Ich würde dennoch gerne den JavaAgenten am Domino laufen lassen und herausfinden
was diese Fehler verursachen könnte.
HCL Domino Server (64 Bit), Release 11.0.1FP3
Mit freundlichen Grüßen,
Benjamin
jBubbleBoy:
Schon mal daran gedacht, den Java-Agenten in einen Java-Server-Task umzuwandeln und so auf dem Domino laufen zu lassen?
mapbug:
Nein, habe ich nicht.
Muss auch zugeben ich weiß auch gar nicht wie das funktioniert.
jBubbleBoy:
Ich habe das einmal, aber vor langer Zeit, mit diesen Quellen umgesetzt:
entwicklercamp.de/konferenz/ent2009.nsf/bc36cf8d512621e0c1256f870073e627/6ebb5e1b95374ea5c12574fe00501b05/$FILE/T3S7-Java%20Add-In%20Servertask.pdf
www.nsftools.com/tips/JavaAddinTest.java
Werner Götz:
Hallo Benjamin,
genau dieselbe Problematik "durfte" ich mal vor etlichen Jahren bei einem Kunden analysieren, letztendlich hatte ich damals auch das Problem und eine Lösung gefunden.
Auch hier war der Code schon vorher von mehreren Stellen auf Auffälligkeiten geprüft worden ;)
Von der Vorgehensweise her hatten wir ein Logging eingebaut, das an etlichen Stellen den verbrauchten bzw. freien Speicher aufgelistet hat.
Hierdurch konnten wir dann erkennen, an welcher Stelle immer mehr Speicher benötigt wird und haben dann diese Stelle genauer analysiert und letztendlich die Lösung gefunden.
Ich glaube, wir hatten dann an verschiedenen Stellen auch mal den Garbage Collector ( System.gc(); ) aufgerufen.
Bei der Analyse sollten die Ergebnisse beim Aufruf am Client, der ja nicht abstürzt ausreichen.
Aber auch am Server ist es natürlich interessant, im Log zu sehen, wie weit der Server gekommen ist, wie sich hier der freie Speicher verändert hat usw.
Ggf. gibt es da ja auch Unterschiede wg. 64 Bit vs. 32 Bit usw.
Die angesprochene Java-Addin-Servertask ist eine sehr interessante Technik, die ich ebenfalls schon in diversen Projekten eingesetzt habe, die aber aus meiner Sicht keine wirkliche Lösung für das aktuelle Problem darstellt und auch nicht zum Szenario passt, wann man diese Technik nutzen sollte.
Wenn man sich damit beschäftigen möchte, sollte man mal nach Andy Brunner (www.abdata.ch) googlen.
Kann schon sein, dass beim Umstellen auf diese Technik die Routine plötzlich durchläuft (schließlich läuft sie auch am Client durch) - das ganze würde dann aber eher daran liegen, dass der für die Routine verfügbare Speicher ein anderer ist als beim Aufruf über den Agentmanager. Und wenn dann im Lauf der Zeit weitere Dokumente im analysierten Datenbestand hinzukommen, könnte auch die neue Technik dann plötzlich wieder abschmieren.
Genauso könnte (bzw. sollte?) man mal mit diversen Parametern bzgl. Java heap size usw. rumspielen, ggf. bekommt man das Problem auch so "umschifft", sollte dann aber im Blick haben, ob sich der freie Speicher im Lauf der Zeit bei weiteren Dokumenten im analysierten Datenbestand verändert.
Viel Erfolg
-Werner
Navigation
[0] Themen-Index
[#] Nächste Seite
Zur normalen Ansicht wechseln