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/VVhX79JDas 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
// 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;
}
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.
public void NotesMain() {
....
try {
// Portale Erstellen
String[] args = null;
Portal.main(args);
// Dump Thread Group
Portal.dumptg(null);
} catch(Exception e) {
e.printStackTrace();
}
}
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.
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
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.
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.
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:
############################################################
### 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)
- 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