Hei,
Minulla on tämmöinen koodi, joka hakee dataa json API:sta. Käytän tuota pätkää ohjelmassani koko ajan loopissa ja haen eri URL osoitteista tietoa. En näe tarpeelliseksi laittaa tänne koko koodia.
Ohjelma saatta pyöriä tuntejakin hyvin, mutta sitten yhtäkkiä se vaan "pysähtyy" ja viimeinen teksti, jonka se sanoo on "Getting trades... jne". Mitään virheitä ei näy eikä ohjelman suoritus keskeydy (Eclipsessä ei lue "terminated").
Mistäköhän tälläinen voisi johtua? Olen antanut sen olla pysähtyneenä useamman tunnin eikä tullut mitään timeout virheitäkään.
lib.conprint("A"); InputStream in=null; boolean error; do { error=false; try { lib.conprint("getTrades: Getting trades since " + since + " ..." ); in = new URL(Global.tradesURL+since.toString()).openConnection().getInputStream(); } catch (Exception e1) { // TODO Auto-generated catch block lib.conprint("Connection error: " + e1); lib.conprint("Reconnecting in 5 seconds..."); lib.sleep(20); //odotetaan 20x250ms error=true; } }while (error); lib.conprint("B");
Kokeile katsoa montako yhteyttä on auki. (windowsilla netstat -n )
Joskus käynyt niin, että kun yhteyksiä ei suljeta ja ne jää auki, eikä roskienkerääjä tajua poimia niitä. Sitten kun maksimimäärä avoimia yhteyksiä on avoinna, se jää vaan odottelemaan että yhteyksiä vapautuu.
Voi tietty olla että on ihan muusta kyse.
Ei noita näytä kerääntyvän. Ehdotuksia miten debugata vielä?
Koodi olisinyt kaikinpuolin muuten valmis, mutta edelleen tätä tapahtuu :( Softasta pitäisi tulla sellainen, että sitä voi ajaa vaikka vuoden, joten tälläinen ei ole sallittua.
Tapahtuu näköjään myös linuxilla. Mitään ehdotuksia debuggaukseen? En keksi oikein mitään.
Grez kirjoitti:
Joskus käynyt niin, että kun yhteyksiä ei suljeta ja ne jää auki, eikä roskienkerääjä tajua poimia niitä.
Pitäisikö nämä yhteydet jotenkin sulkea erikseen? En ole huomannut, että tuo vika tulisi säännöllisesti tietyn ajan jälkeen. Joskus ohjelma pyörii monta päivää.
EDIT: Löysin tälläisen ja taidan kokeilla tuossa vikassa viestissä olevaa koodia: http://stackoverflow.com/questions/7439463/java-url-hangs-and-never-reads-in-website
Kokeillaas taas muutama päivä...
public String getData(String URL){ String data=""; try { URL link = new URL(URL); BufferedReader in = new BufferedReader(new InputStreamReader(link.openStream())); //InputStream in = link.openStream(); String inputLine = ""; while ((inputLine = in.readLine()) != null) { data = data + inputLine; } in.close(); } catch(Exception e){ lib.conprint2("\n\t\tConnection error: " + e,false); lib.writeLog("errors", "getData() error: " + e + "\n" + data,true,true); data=""; } return data; }
JussiR kirjoitti:
Ei noita näytä kerääntyvän.
Miten katsoit?
JussiR kirjoitti:
Pitäisikö nämä yhteydet jotenkin sulkea erikseen?
Kai close-metodikin on tarkoituksella olemassa?
Metabolix kirjoitti:
JussiR kirjoitti:
Ei noita näytä kerääntyvän.
Miten katsoit?
Linuxilla "netstat -ntap".
Tuo vika tuli taas vaikka käytössä on nyt tuo getData metodi. Tuolla java prosessilla ei ole netstat komennon mukaan mitään yhteyttä mihinkään ja CPU käyttö on 0%.
Samaan aikaan kun tuo vika tuli, mulla meni kaikkien koneiden netti tosi hitaaksi. Puolet IRC servuista ping timeouttasi yms ja nettisivuilla kesti monta minuuttia aueta.
Kaikki muu palasi puolessa tunnissa normaaliksi paitsi mun java ohjelma, joka pysyyy jumissa tuossa "Get 5 min avg. price since ID 1390570541110572"
Vois varmaan värkätä jotain tuon getData:n while loopin sisälle debuggausta varten. Onko mahdollista, että link.openStream() olisi "null" koko ajan, kun verkkoon tule jotain vikaa?
Ainakin jos katkaisen koneesta netin ihan normaalisti, tulee UnknownHostException.
Ajattelin laittaa semmoisen, että se pysyy tuossa while loopissa enintään 60 s.
Oletko varma, että et aiheuta ikuisella silmukalla sellaista kuormitusta, että esimerkiksi verkkosi reititin tai tukiasema tilttaisi? Myös vastaanottavalta palvelimelta voi joskus saada hetkelliset bannit, jos tekee liikaa pyyntöjä lyhyessä ajassa.
Kyl mä aika varma oon, kun sitä dataa haetaan vain n. 5 min välein ja silloinkin jotain 5 KB 5-10 kertaa peräkkäin ja niiden hakujen välissäkin 200 ms tauko. API palauttaa vain 100 rivillistä (pieniä) json objekteja kerralla. Muistaakseni jos tuo palvelu antaa bännit, sieltä tulee jokin ilmoitus kyselyihin ja se bänni ei lähde hetkessä pois.
Muut softat, jotka käyttää samaa API:a näyttää hakevan joka sekunti dataa. Tosin ne hakee eri dataa.
En ole varma "hajosiko" mun verkkoyhteys ennen vai jälkeen tuon viimeisimmän haun, johon se jäi, kun sitä ennen oli juurikin tuo 5 min tauko. Reitittimen prossunkäyttö ja kaikki näytti hallinnan sivulla normaalilta.
Kokeilen nyt tämmöistä. Myöhemmin ehkä tuo URL-luokka vaihtoon johonkin muuhun.
public String getData(String URL){ String data=""; int endTime=(int) (System.currentTimeMillis() / 1000L)+180; // 3 min without/with data and we'll stop try { URL link = new URL(URL); BufferedReader in = new BufferedReader(new InputStreamReader(link.openStream())); //InputStream in = link.openStream(); String inputLine = ""; while ((inputLine = in.readLine()) != null) { data = data + inputLine; if((int) (System.currentTimeMillis() / 1000L)>endTime){ lib.conprint2("\n\t\tConnection error: we are hanging in here for some reason",false); lib.writeLog("errors", "getData() error: we are hanging in here for some reason\n" + data,true,true); in.close(); data=""; break; } } in.close(); } catch(Exception e){ lib.conprint2("\n\t\tConnection error: " + e,false); lib.writeLog("errors", "getData() error: " + e + "\n" + data,true,true); data=""; } return data; }
Nyt jäi taas "jumiin" eikä tuo koodi ilmoittanut mitään. Mitäköhän tässä pitäis tehdä?
1. Jumituskohta on tämä:
BufferedReader in = new BufferedReader(new InputStreamReader(link.openStream()));
2. Jumiutumisen (joka ei koskaan lopu) aikana ei ole yhteyttä auki
3. Prosessin CPU käyttö on jumiutumisen aikana 0%
4. Vähintään sekunnin ennen ja jälkeen jumiutumisen alun, on mahdollista yhdistää serverille, mutta jumitushetken alusta ei ole tietoa. Tuo ~1 sekunti tulee siitä, kun olen kokeillut juuri silloin manuaalisesti.
Jos et saa vian syytä selville, voit kokeilla purkkaviritelmää: laita tuo rivi eri säikeeseen ja yritä keskeyttää se, jos se jumiutuu.
Thread jumi = new Thread() { public void run() { in = new BufferedReader(new InputStreamReader(link.openStream())); } }; jumi.start(); jumi.join(aikaraja); if (jumi.isAlive()) { System.err.println("Keskeytetään..."); jumi.interrupt(); jumi.join(); System.err.println("Keskeytetty!"); }
Kiitos, kokeilin tuota.
Samalla, kun interruptoin threadin sen jumiutumisen jälkeen, poikkeus tuosta URL luokasta:
java.net.ConnectException: Connection timed out
Jos interruptoin vaikka ei jumita, tulee eri poikkeus: java.net.SocketException: Connection reset
EDIT: nyt se oli näköjään mennyt yöllä monta kertaa peräkkäin jumiin ja lopulta jäänyt jumiin interrupt() kohtaan eli threadia ei saatu keskeytettyä.
Taidanpa ottaa Apache HttpClient käyttöön.
EDIT: Ihan samat ongelmat Apache HttpClientin kanssa. Välillä interrupt() kohtaan ei jäädä ikuisesti jumiin vaan esim. vartiksi.
12:34:44: getData(): the thread is hanging. Interrupting... 12:51:50: org.apache.http.impl.execchain.RetryExec execute INFO: I/O exception (java.net.SocketException) caught when processing request: Connection timed out 12:51:50: org.apache.http.impl.execchain.RetryExec execute INFO: Retrying request 12:51:53: getData(): thread interrupted succesfully
Kokeilin stop() komentoa ja sillä pysäyttäminen onnistuu aina, mutta kestää 69 sekuntia. Hmm, mistäköhän tuo aika tulee? 60 sekuntia voisi olla jokin timeout...
13:10:53: getData(): the thread is hanging... 13:12:02: getData(): dataGet thread stopped succesfully 13:14:08: getData(): the thread is hanging... 13:15:17: getData(): dataGet thread stopped succesfully 13:17:23: getData(): the thread is hanging... 13:18:32: getData(): dataGet thread stopped succesfully
Tässä on tällä hetkellä käytössä oleva getData() metodi kokonaisuudessaan:
@SuppressWarnings("deprecation") public String getData(final String url){ stop=false; data=""; Thread dataGet = new Thread() { public void run() { StringBuffer result = new StringBuffer(); HttpClient client = HttpClientBuilder.create().build(); HttpResponse response = null; try { HttpGet request = new HttpGet(url); request.addHeader("User-Agent", "Advanced-java-client API v2"); response = client.execute(request); BufferedReader rd = null; rd = new BufferedReader( new InputStreamReader(response.getEntity().getContent())); String line = ""; while ((line = rd.readLine()) != null && stop==false) { result.append(line); } } catch (Exception e) { lib.error("getData() error: " + e + (response==null ? "" : " (response code: " + response.getStatusLine().getStatusCode() + ")")); }finally{ data=result.toString(); } } }; dataGet.start(); try { dataGet.join(120000); // 2 min } catch (InterruptedException e) { lib.conprint3(""); lib.error("getData(): dataGet.join A error: " + e + (data.equals("") ? "" : " - Data: " + data)); stop=true; data=""; e.printStackTrace(); } if(dataGet.isAlive()){ lib.conprint3(""); lib.error("getData(): the thread is hanging... " + (data.equals("") ? "" : "Data: " + data)); stop=true; dataGet.stop(); data=""; try { dataGet.join(); } catch (Exception e) { lib.error("getData(): dataGet.join B error: " + e); e.printStackTrace(); }finally{ lib.conprint("getData(): dataGet thread stopped succesfully"); } } return data; }
Jahas nyt ei ollut pysähtynyt edes stop() komennolla. On se nyt vi**u... Kolme kuukautta jo täs testaillu... Vielä ehdotuksia tuon thread purkan sijaan?
Kokeilin nyt sitten jättää koko threadin päälle, kun sitä ei aina saa pysäytettyä, mutta laittaa tuon stop booleanin todeksi ettei tapahdu mitään hassua. Kolmen jumiutumisen jälkeen java kaatui, mutta ei oo varmaan mikään ihme tälläisellä pelleilyllä:
# A fatal error has been detected by the Java Runtime Environment: # # Internal Error (os_linux_zero.cpp:236), pid=26968, tid=1753244816 # Error: caught unhandled signal 11 # # JRE version: 6.0_18-b18 # Java VM: OpenJDK Zero VM (14.0-b16 mixed mode linux-arm ) # Derivative: IcedTea6 1.8.4 .... monta sataa riviä ..... Java Threads: ( => current thread ) =>0x68a00468 JavaThread "Thread-3208" [_thread_in_native, id=31767, stack(0x68687000,0x68807000)] 0x001aa630 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=26986, stack(0x67dc7000,0x67f47000)] 0x00087ad8 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=26974, stack(0x67b65000,0x67ce5000)] 0x00086448 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=26973, stack(0x679e5000,0x67b65000)] 0x000718e8 JavaThread "Finalizer" daemon [_thread_blocked, id=26972, stack(0x67665000,0x677e5000)] 0x000705c0 JavaThread "Reference Handler" daemon [_thread_blocked, id=26971, stack(0x674e5000,0x67665000)] 0x0001e5f8 JavaThread "main" [_thread_blocked, id=26969, stack(0x40dd2000,0x40f51000)]
URLConnectionilla ei välttämättä ole oletuksena mitään timeoutia. Eli jos palvelin ei anna mitään dataa yhteyden avauksen jälkeen niin ohjelma jää odottamaan ikuisesti. Kokeile asettaa timeout kuten alla.
URLConnection urlConnection = new URL("...").openConnection(); urlConnection.setConnectTimeout(5000);
Moni palvelin ei myöskään automaattisesti sulje yhteyttä kun kaikki data on luettu joten readLine() ei välttämättä koskaan palauta nullia.
Aihe on jo aika vanha, joten et voi enää vastata siihen.