Otann / morse

📡 Clojure interface for Telegram Bot API
Eclipse Public License 1.0
257 stars 48 forks source link

Exception causes long polling process shutdown #17

Closed martosaur closed 7 years ago

martosaur commented 7 years ago

OK, I'm a complete clojure rookie, but I think this is what's happening: If background process performing long-polling encounters an exception (for example 502 from the api) it shuts down and stops polling updates, which is not nice. An example exception:

user=> Exception in thread "async-dispatch-32" java.lang.Error: java.io.EOFException: SSL peer shut down incorrectly
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1148)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at sun.security.ssl.InputRecord.read(InputRecord.java:505)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at org.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:573)
    at org.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:447)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.updateSecureConnection(DefaultClientConnectionOperator.java:219)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.layerProtocol(ManagedClientConnectionImpl.java:421)
    at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:815)
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:616)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:447)
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:884)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
    at clj_http.core$request.invokeStatic(core.clj:304)
    at clj_http.core$request.invoke(core.clj:208)
    at clojure.lang.Var.invoke(Var.java:379)
    at clj_http.client$wrap_request_timing$fn__11582.invoke(client.clj:835)
    at clj_http.headers$wrap_header_map$fn__9803.invoke(headers.clj:143)
    at clj_http.client$wrap_query_params$fn__11485.invoke(client.clj:651)
    at clj_http.client$wrap_basic_auth$fn__11492.invoke(client.clj:677)
    at clj_http.client$wrap_oauth$fn__11496.invoke(client.clj:687)
    at clj_http.client$wrap_user_info$fn__11501.invoke(client.clj:700)
    at clj_http.client$wrap_url$fn__11568.invoke(client.clj:801)
    at clj_http.client$wrap_redirects$fn__11267.invoke(client.clj:267)
    at clj_http.client$wrap_decompression$fn__11292.invoke(client.clj:339)
    at clj_http.client$wrap_input_coercion$fn__11422.invoke(client.clj:518)
    at clj_http.client$wrap_additional_header_parsing$fn__11443.invoke(client.clj:552)
    at clj_http.client$wrap_output_coercion$fn__11413.invoke(client.clj:468)
    at clj_http.client$wrap_exceptions$fn__11253.invoke(client.clj:219)
    at clj_http.client$wrap_accept$fn__11457.invoke(client.clj:595)
    at clj_http.client$wrap_accept_encoding$fn__11463.invoke(client.clj:609)
    at clj_http.client$wrap_content_type$fn__11452.invoke(client.clj:585)
    at clj_http.client$wrap_form_params$fn__11546.invoke(client.clj:765)
    at clj_http.client$wrap_nested_params$fn__11563.invoke(client.clj:790)
    at clj_http.client$wrap_method$fn__11506.invoke(client.clj:707)
    at clj_http.cookies$wrap_cookies$fn__8753.invoke(cookies.clj:124)
    at clj_http.links$wrap_links$fn__10040.invoke(links.clj:51)
    at clj_http.client$wrap_unknown_host$fn__11572.invoke(client.clj:810)
    at clj_http.client$get.invokeStatic(client.clj:913)
    at clj_http.client$get.doInvoke(client.clj:909)
    at clojure.lang.RestFn.invoke(RestFn.java:423)
    at morse.api$get_updates.invokeStatic(api.clj:17)
    at morse.api$get_updates.invoke(api.clj:10)
    at morse.polling$create_producer$fn__11694$fn__11722$state_machine__6688__auto____11723$fn__11725.invoke(polling.clj:24)
    at morse.polling$create_producer$fn__11694$fn__11722$state_machine__6688__auto____11723.invoke(polling.clj:24)
    at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:1011)
    at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:1010)
    at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:1015)
    at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:1013)
    at morse.polling$create_producer$fn__11694$fn__11722.invoke(polling.clj:24)
    at clojure.lang.AFn.run(AFn.java:22)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    ... 2 more

If this is intentional, then I'd appreciate any hints on how to tackle this on application level :)

Otann commented 7 years ago

Oh, shoot! Yes, you're right, there should be a wrapper that catches exceptions in the handler.

But on the other hand, I would advise to only receive updates in the handler and process them also asynchronously with your favorite async model.

For me, this would be putting incoming messages to a channel in a handler and set of workers that take data from that channel and process it.

martosaur commented 7 years ago

@Otann thanks for the response! Looks like it's time to get myself familiar with clojure's async tools. ^_^ thanks once again