Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem mit Kursaktualisierung von Webseiten #478

Closed
hjbflyer opened this issue Mar 24, 2016 · 35 comments
Closed

Problem mit Kursaktualisierung von Webseiten #478

hjbflyer opened this issue Mar 24, 2016 · 35 comments
Labels
bug

Comments

@hjbflyer
Copy link
Contributor

@hjbflyer hjbflyer commented Mar 24, 2016

Ich habe ein merkwürdiges Verhalten bei der Aktualisierung von alten und neuen Kursen von Webseiten.

  1. Wenn ich ein neues Wertpapier anlege und die historischen Kurse über onvista.de abrufe, erscheinen diese in der Tabelle und alles ist gut. Standardmässig werden ja nur 3 Monate geholt. Wenn ich jetzt die URL editiere und den Parameter &RANGE=120M anfüge verschwinden die historischen
    Daten im Dialog. Kopiere ich die URL in den Browser, werden die Daten korrekt geholt und im Browser angezeigt. Beim Beenden des Dialogs beantworte ich die Frage ob die alten Daten gelöscht werden sollen mit ja. Also sind die alten Daten weg und da die neuen nicht geholt oder angezeigt werden ist
    alles weg.
  2. Wenn ich das Programm neu starte, sehe ich, dass Daten geholt werden. Im Log steht aber "Read Time Out". Ist dieser Wert eventuell zu klein? Kann man den Wert eventuell parametrisieren?
  3. Bei der manuelle Aktualisierung hat es dann geklappt. (ging wohl schnell genug)
@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Mar 24, 2016

Ich habe noch eine Anmerkung zu obigem Thema.
in der Klasse HTMLTableQuoteFeed wird in der Methode extractPrice auf einen TabellenHeader
verglichen
if (cells.size() == 0) return null;

Müsste es hier nicht heissen?
if (cells.size() <= 1) return null;

Da es über Tabelle noch eine Zwischenüberschrift mit einem Element gibt.

@buchen
Copy link
Owner

@buchen buchen commented Mar 24, 2016

Müsste es hier nicht heissen?
if (cells.size() <= 1) return null;

Könnte man machen. Eine Zeile wird aber auch übersprungen wenn der Wert nicht geparst werden kann (z.B. weil es einen Seitennavigator in der Tabelle gibt) oder weil es eine Zelle mit diesem Index nicht gibt.

Das Verhalten, das Du beschreibst, scheint auch weniger auf ein inhaltliches Problem bei parsen der HTML Daten hinzudeuten sondern auf ein zeitliches (Read Time Out). Der Download der Daten findet hier statt. Ich kenne Jsoup nicht so gut, dass ich direkt sagen könnte, wie und wo man da mit Timeouts eingreifen könnte. Wenn Du Dich versuchen möchtest: in der Klasse gibt es zu Testzwecken auch eine main Methode. Als Argument kannst Du die URL übergeben.

@buchen buchen added the bug label Mar 24, 2016
@buchen buchen added this to the 2016 Q1 Short-List milestone Mar 24, 2016
@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Mar 25, 2016

Die Fehler entstehen in der Tat durch Timeouts. Setzt man den Timeout auf 0 oder auf einen hinreichend großen Wert, dann werden alle Seiten fehlerfrei empfangen.

Ich glaube es ist aber ein Thread-Problem und Aktualisierungsproblem. Im Debugger habe ich gesehen, dass Du die Wertpapiere 2x hintereinander aktualisierst. (Einmal im Worker1 und einmal im Worker2). Wenn der Timeout auf 0 oder 20sec steht, laufen die Threads abwechselnd jeweils mit dem gleichen Wertpapier.

Wäre es nicht sinnvoll 5 oder 10 Threads zu haben die parallel verschiedene Wertpapiere abfragen?

Vielleicht habe ich aber das Vorgehen noch nicht richtig verstanden.

@buchen
Copy link
Owner

@buchen buchen commented Mar 25, 2016

Im Debugger habe ich gesehen, dass Du die Wertpapiere 2x hintereinander aktualisierst.

Die doppelten Aufrufe sind historisch bedingt. Yahoo unterscheidet zwischen "latest" und "historic" Kursen. Das habe ich auf den HTML Download einfach übertragen. Eigentlich steht da mal ein grösseres Refactoring an... (da fehlt noch mehr: man will z.B. auch $ Kurse ggf. in EUR umwandeln können, etc.).

Eigentlich habe ich aber einen Cache eingebaut so dass nicht wirklich zwei Requests gemacht werden sollten. Der zieht bei Dir aber nicht? Dann muss ich mir das noch mal anschauen.

Setzt man den Timeout auf 0 oder auf einen hinreichend großen Wert, dann werden alle Seiten fehlerfrei empfangen.

Mach mal einen PR mit dem Timeout auf - das kann ich ja ändern. 😄

Wäre es nicht sinnvoll 5 oder 10 Threads zu haben die parallel verschiedene Wertpapiere abfragen?

Klar, das könnte man ändern. Für meine eigene Datei geht das bisher schnell genug so dass ich bisher keine Bedarf hatte das umzubauen. Der UpdateQuotesJob lädt die Kurse.

buchen added a commit that referenced this issue Mar 25, 2016
@buchen
Copy link
Owner

@buchen buchen commented Mar 25, 2016

okay, das mit dem timeout war einfach... 👍

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Mar 25, 2016

Ich habe bei mir 27 Papiere in meiner Wertpapierliste. Da beim Programmstart alle 27 2mal aktualisiert werden, dauert der ganze Vorgang über 5 Minuten. Der Cache kommt dabei noch nicht zum Einsatz.

@buchen
Copy link
Owner

@buchen buchen commented Mar 25, 2016

Der Cache kommt dabei noch nicht zum Einsatz.

Hast Du PP in Eclipse laufen? Könntest Du mal debuggen warum der Cache nicht zieht?

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Mar 25, 2016

Wie es aussieht ist es ein Timing-Problem. Wenn die erste URL "geparsed" wird (Worker1), wird die
gleiche URL im Worker2 gestartet, bevor das Ergebnis aus Worker1 in den Cache gesteckt wird.

@buchen
Copy link
Owner

@buchen buchen commented Mar 25, 2016

Autsch. Ich starte zwei Jobs. Ja, ist alles in die Jahre gekommen... 😁 Ich überlege mir was.

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Mar 25, 2016

Mit dem aktuellen Code sind die Timeout-Probleme zumindest weg. Es bleiben aber noch jede Menge
ParseExceptions. Auch wenn sie keine Auswirkungen haben, sind diese Meldungen doch unschön.
!SUBENTRY 2 name.abuchen.portfolio.ui 4 0 2016-03-25 12:40:09.613 !MESSAGE Kursliste 3 Monate !STACK 0 java.text.ParseException: Kursliste 3 Monate at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed$DateColumn.setValue(HTMLTableQuoteFeed.java:131) at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.extractPrice(HTMLTableQuoteFeed.java:456) at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.parse(HTMLTableQuoteFeed.java:344) at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.parseFromURL(HTMLTableQuoteFeed.java:307) at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.internalGetQuotes(HTMLTableQuoteFeed.java:271) at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.updateLatestQuotes(HTMLTableQuoteFeed.java:220) at name.abuchen.portfolio.ui.UpdateQuotesJob.doUpdateLatestQuotes(UpdateQuotesJob.java:111) at name.abuchen.portfolio.ui.UpdateQuotesJob.run(UpdateQuotesJob.java:58) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

Ich schlage vor, doch die Abfrage auf
if (cells.size() <= 1) { return null; }

zu ändern. Dann würden diese Meldungen nicht mehr im Fehlerprotokoll landen.

buchen added a commit that referenced this issue Mar 25, 2016
@buchen
Copy link
Owner

@buchen buchen commented Mar 25, 2016

Ich schlage vor, doch die Abfrage auf
if (cells.size() <= 1) { return null; }

Habe ich gemacht. Da eine gültige Zeile mindestens 2 Spalten braucht (Datum + Kurs), kann man die hier aussortieren. Und das reduziert die Exceptions doch deutlich.

@buchen
Copy link
Owner

@buchen buchen commented Mar 27, 2016

Ich habe die Download jobs jetzt parallelisiert - sollte deutlich schneller sein. 👍 Freue mich über weitere Feedback - ggf. den Issue einfach wieder aufmachen.

@buchen buchen closed this Mar 27, 2016
@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Mar 27, 2016

Super für die schnelle Bearbeitung. Nur muss da leider noch ein Fehler drin sein, denn alle
Request erzeugen Fehler und enthalten im Log die HTML-Datei
`!STACK 0
java.io.IOException:

... `

Wahrscheinlich schlägt wieder ein Timeout zu.

@buchen
Copy link
Owner

@buchen buchen commented Mar 27, 2016

Was ist die URL des Wertpapiers? Zum Testen... meine Webseiten konnten aufgerufen werden.

@buchen buchen reopened this Mar 27, 2016
@buchen
Copy link
Owner

@buchen buchen commented Mar 27, 2016

Beide URLs tun bei mir 😬

Im Prinzip ist ja HTML Code zurückgekommen. Wenn Du den speicherst und im Browser öffnest, was steht da? Und könntest Du den Stack Trace posten?

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Mar 27, 2016

Es ist eine Webseite, die unter anderem einen Fehlertext enthält

50x Error

Ihre Anfrage konnte nicht bearbeitet werden. Bitte versuchen Sie es zu einem späteren Zeitpunkt noch einmal.

Der Stacktrace ist:

name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.parse(HTMLTableQuoteFeed.java:361)
    at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.parseFromURL(HTMLTableQuoteFeed.java:307)
    at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.internalGetQuotes(HTMLTableQuoteFeed.java:271)
    at name.abuchen.portfolio.online.impl.HTMLTableQuoteFeed.updateLatestQuotes(HTMLTableQuoteFeed.java:220)
    at name.abuchen.portfolio.ui.UpdateQuotesJob$1.run(UpdateQuotesJob.java:123)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

@buchen
Copy link
Owner

@buchen buchen commented Mar 27, 2016

Eher kein Timeout Problem. Vielleicht zu viele Requests auf einmal zu der Webseite? Ich kann mir vorstellen, dass es eine Art "throtteling" vom Server ist bei zu vielen (parallelen) Requests.

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Mar 27, 2016

Wie kriegen wir die Kuh vom Eis?

@buchen
Copy link
Owner

@buchen buchen commented Mar 27, 2016

Bisher nur eine Theorie. Könntest Du mir mal Deine Datei (Konten und Depots vorher löschen) schicken? Dann habe ich genug URLs um das selber auszuprobieren. portfolio.performance.help@gmail.com

Wenn es an zu vielen Requests liegt, dann könnte man die pro Domain reduzieren.

buchen added a commit that referenced this issue Apr 3, 2016
@buchen
Copy link
Owner

@buchen buchen commented Apr 3, 2016

Vielen Dank für die Beispieldatei. Ich habe etwas damit rumgespielt. Ab 4 parallelen Downloads sind keine Kurse mehr im HTML (nur noch die Fehlermeldung). Bei einem, zwei, oder drei parallelen Downloads werden Kurse geladen. Aber: es dauert immer genauso lang (bei mir ca. 160 Sekunden). Da scheint server-seitig ein throtteling stattzufinden.

Ich habe den Code jetzt mal wie folgt geändert: es werden bis zu 10 Kurse parallel runtergeladen, aber maximal ein Request pro Host. Schau mal ob das bei Dir tut.

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Apr 3, 2016

Ich werde es mit heute Nachmittag anschauen. Vielen Dank.

buchen added a commit that referenced this issue Apr 3, 2016
Issue: #478
@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Apr 3, 2016

Hast Du die Target-Platform geändert? "org.eclipse.emf.common" in der Version 2.11.1 ist nicht in der alten TargetPlatform enthalten.

@buchen
Copy link
Owner

@buchen buchen commented Apr 3, 2016

Nicht Target Platform, aber die benötigten Bundles. Am einfachsten die Run Konfiguration noch mal neu generieren.

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Apr 3, 2016

Habe eine MVN Version gebaut. Das Verhalten ist noch etwas merkwürdig. Die Anzeige bleibt bei "27 operations remaining" hängen. (Das sind glaube ich meine HTMLUpdates). Nach 2,5 Minuten geht es weiter und es ist alles auf einen Schlag beendet. Fehler stehen keine im Logfile.
Ich will mal sehen ob das Programm wieder in der IDE zum laufen bekommen, damit en Debugger nutzen kann.

@buchen
Copy link
Owner

@buchen buchen commented Apr 3, 2016

Nach 2,5 Minuten geht es weiter und es ist alles auf einen Schlag beendet.

Das Timeout für die gesamt Aktien ist 2,5 Minuten. Da hängt er also. Ich habe mit Deiner Datei getestet, aber alle anderen außer den Onvista rausgeslöscht. Ich wollte nur mit den HTML Tabellen testen. Ich probiere es ebenfalls noch mal mit der kompletten Datei.

Ich will mal sehen ob das Programm wieder in der IDE zum laufen bekommen, damit en Debugger nutzen kann.

Versuche noch mal das Programm aus der Product Datei zu starten: https://github.com/buchen/portfolio#run-program Dann sollten die Abhängigkeiten neu gesetzten werden.

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Apr 3, 2016

Danke für den Tipp mit der Product-Datei.

Bevor Du Deine Änderungen gemacht hast, habe ich lokal das Programm so geändert, dass nur 1 Thread verwendet wurde. Dabei war der Timeout für das erste Holen der aktuelle Kurse entscheidend. Ich habe diesen Wert auf Anzahl der HTML-Links mal Einzel-Tipout gesetzt. Das war zwar langsam (ca. 15 sec pro Abfrage), hat aber funktioniert. Das Abholen der historischen Daten ging danach sehr schnell, weil ich vermute, dass die Daten aus dem Cache kamen (sind ja die gleichen Links).

Aber vielleicht habe ich ja auch die Update--Strategie noch nicht richtig verstanden.

So wie ich den Join verstehe, wird solange gewartet bis alle Jobs fertig sind oder der Timeout abgelaufen ist. Warum es überhaupt nicht weitergeht verstehe ich nicht nicht.

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Apr 4, 2016

Ich würde keinen festen Timeout verwenden, sondern einen Timeout, der sich aus der Anzahl der Wertpapiere berechnet.

Auf der anderen Seite scheint der Timeout keine Rolle mehr zu spielen, da die Abfragen davon unabhängig im Hintergrund passieren und nicht mehr mit dem Aufruf zu synchronisieren.

@buchen
Copy link
Owner

@buchen buchen commented Apr 4, 2016

In der Doku heißt es:

timeoutMillis - the maximum amount of time to wait for the join to complete, or zero for no timeout.

Macht wohl mehr Sinn hier 0 einzutragen, damit der Benutzer auch Feedback bekommt wenn es hängt.

Hast Du rausfinden können warum es hängt?

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Apr 5, 2016

Wie es aussieht ist es ein Timing-Problem mit den verschiedenen Jobs, verbunden mit der Tatsache, dass die ProgressMonitore dabei auch nicht richtig anzeigen.

1.Der automatische UpdateQuotesJob, hat nur den NullProgressManager, deshalb wird der Fortschritt bei des Kursaktualisierung nicht angezeigt.
2. Da der Join-Timout zu klein ist, wird der Abgleich der historischen Daten schon gestartet, während die aktuellen Kurse noch geholt werden. Hier ist der ProgressMonitor gesetzt und es erscheint eine Fortschrittsanzeige. Da sich die beiden Jobs überholt haben, bleibt diese Anzeige eventuell stehen bis der Timeout abgelaufen ist.

Eine Lösung wäre den Join-Timout auf 0 zu setzen. Dann geht es mit den historischen Daten erst weiter wenn alle aktuellen Kurse geholt sind. Alternativ kann man den Timeout auch auf
Anzahl der Kursabfragen * TIMEOUTsetzen. Auf jeden Fall sollte aber auch der IProgressMonitor richtig gesetzt werden. Auf keinen Fall würde ich einen festen Wert (ausser 0) für den Timeout eintragen.

Es hängt also nichts, sondern es ist nur ein Anzeige-/Timing-Problem.

@buchen
Copy link
Owner

@buchen buchen commented Apr 6, 2016

Es hängt also nichts, sondern es ist nur ein Anzeige-/Timing-Problem.

Okay.

Durch die SchedulingRule kann auch ein Update des aktuellsten Kurses nicht parallel zu einem Update der historischen Kurse laufen (immer auf einen Hostnamen bezogen). Im Prinzip bräuchte ich jetzt nicht mehr zwei JobGroups sondern eine würde reichen. Mal sehe ob ich am Wochenende dazu komme. Im Prinzip steht noch mehr Refactoring an, aber dazu komme ich nicht in naher Zukunft.

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Apr 12, 2016

Hallo Andreas,
ich weiss nicht wie weit Deine Pläne mit dem Umbau gedien sind. In der Zwischenzeit habe ich noch ein paar Untersuchungen gemacht.

  1. Problem: Die Fortschrittsanzeige - Nach dem Öffnen des ersten Portfolios, erscheint in der linken unteren Ecke keine Fortschrittsanzeige. Beim Öffnen eines 2. Portfolios funktioniert die Anzeige. Sie funktioniert auch wenn nach 10 Minuten die Kurse erneut abgerufen werden.
  2. Problem: JOIN - Bei einem Timeout von 10. Sekunden für den ersten JOIN, erfolgt 10 Sekunden keine Anzeige oder es werden die Aufträge herunter gezählt. Nachdem der Timeout abgelaufen ist, werden die historischen Daten abgerufen und es erscheint die Anzeige es sind noch 27 Aufträge abzuarbeiten. Diese Anzeige bleibt etwa 2:40 unverändert stehen. (Ich dachte zunächst es ist der 2. Join Timeout. Aber solange dauert es die 27 Kurse sequentiell abzuarbeiten.

Werden die Kurse später manuell per Menü abgeholt, erscheint wieder die Anzeige „27 operations remaining“ für ca. 10 Sekunden.

Irgendwie beeinflussen sich die Jobs ( was mich ein wenig beunruhigt).

Ich habe für mich beide Timeouts auf 0 gestellt. Da behebt zwar nicht die Anzeigeprobleme - aber die Aufträge werden so nacheinander abgearbeitet.

Hast Du bei der Jobarchitektur auch daran gedacht, dass mehrere Portfolios geöffnet sein können?

Ich hoffe, ich konnte ein wenig weiterhelfen.

Gruß,
Achim

buchen added a commit that referenced this issue Apr 16, 2016
* Schedule all jobs (latest or historic) at once
* Update the dirty state of the GUI after every 5th job
* Removed scheduling rule that prevents parallel jobs for one client

Issue: #478
@buchen
Copy link
Owner

@buchen buchen commented Apr 16, 2016

Problem: Die Fortschrittsanzeige

Okay, ich glaube ich habe das Problem verstanden. Wenn das GUI erstellt wird, dann registriert sich die Komponente als ProgressProviderFactory. Wenn der Job aber vorher gestartet wird, dann ist die Factory noch nicht registriert und es wird ein NullProgressMonitor angelegt. Und natürlich erscheinen dann keine Meldungen im GUI.

Wenn ich den Job mit 1000 Millisekunden delay starte, dann tut es meist. Ich belasse es jetzt mal dabei. Es ist ja erst mal "nur" ein Anzeigenproblem. Ich denke man könnte das PortfolioPart refactoren: das PortfolioPart dient als ProgressMonitorFactory. Und aktualisiert das GUI wenn es denn (schon | noch) existiert.

Ich habe mit zwei gleichzeitig geöffneten Dateien getestet. Bei mir sieht das gut aus.

es erscheint die Anzeige es sind noch 27 Aufträge abzuarbeiten. Diese Anzeige bleibt etwa 2:40 unverändert stehen.

Ich vermute es liegt daran: zwar ist der Timeout von dem ersten Job schon abgelaufen, aber die einzelnen Aktualisierungsjobs laufen noch. Und für einen Host ("www.yahoo.com") kann immer nur einer laufen. D.h. die Jobs aus der zweiten Gruppe sind noch blockiert. Und prompt läuft auch die zweite Job Gruppe in den Timeout.

Ich habe jetzt die Timeouts auf 0 gesetzt.

Irgendwie beeinflussen sich die Jobs ( was mich ein wenig beunruhigt).

Momentan darf immer nur 1 Job für den HTML Download pro Host ("www.yahoo.com") gleichzeitig laufen. Diese Job Scheduling Rule gilt Datei-übergreifend. Diese Regel habe ich eingebaut, weil wir gesehen haben, dass ab einer bestimmten Anzahl von parallelen Jobs keine Kurse mehr im HTML vorhanden sind.

@hjbflyer
Copy link
Contributor Author

@hjbflyer hjbflyer commented Apr 17, 2016

Hallo Andreas,
wie es aussieht, scheint jetzt alles zu funktionieren. Alle Updates (aktuell und historisch) werden in eine Work-Queue getan. Die Anzeige wird auch richtig aktualisiert und auch die Jobs aus verschiedenen Portfolio werden richtig synchronisiert.

@buchen
Copy link
Owner

@buchen buchen commented Apr 17, 2016

Danke für die Tests! Schauen wir mal wie weit wir mit dieser Implementierung kommen...

@buchen buchen closed this Apr 17, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.