telegram
telegram copied to clipboard
No reconnect on connecton issues
I tried to start my bot when the Internet connection was absent and it (obviously) failed with java.net.UnknownHostException: api.telegram.org exception (the full stack trace is below).
The issue is that it hasn't tried to reconnect after that and there seem to be no examples or docs about how to handle connection exceptions and may be kick off a reconnect from the code.
Is it possible to detect it in the current version of the code? If not, can either automatic reconnects, or error callbacks, or examples (if it's already there) be added?
2023-02-10 13:25:09.009 ERROR ScalajHttpClient:39 - RESPONSE XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX {}
java.net.UnknownHostException: api.telegram.org
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:607)
at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:293)
at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:558)
at sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:264)
at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:367)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:203)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1207)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1056)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:189)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1572)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1500)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:352)
at scalaj.http.HttpRequest.doConnection(Http.scala:367)
at scalaj.http.HttpRequest.exec(Http.scala:343)
at scalaj.http.HttpRequest.asString(Http.scala:492)
at com.bot4s.telegram.clients.ScalajHttpClient.$anonfun$sendRequest$12(ScalajHttpClient.scala:104)
at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1$$anon$2.block(ExecutionContextImpl.scala:59)
at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3313)
at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1.blockOn(ExecutionContextImpl.scala:70)
at scala.concurrent.BatchingExecutor$AsyncBatch.blockOn(BatchingExecutor.scala:202)
at scala.concurrent.package$.blocking(package.scala:124)
at com.bot4s.telegram.clients.ScalajHttpClient.$anonfun$sendRequest$11(ScalajHttpClient.scala:105)
at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:661)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:430)
at scala.concurrent.BatchingExecutor$AbstractBatch.runN(BatchingExecutor.scala:134)
at scala.concurrent.BatchingExecutor$AsyncBatch.apply(BatchingExecutor.scala:163)
at scala.concurrent.BatchingExecutor$AsyncBatch.apply(BatchingExecutor.scala:146)
at scala.concurrent.BlockContext$.usingBlockContext(BlockContext.scala:107)
at scala.concurrent.BatchingExecutor$AsyncBatch.run(BatchingExecutor.scala:154)
at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:175)
Could you share the code that you are using ? It would help me give you some pointers on how to deal with this exception, there is indeed nothing in the doc about that but that could be handled pretty much the same way any exception would (we won't retry inside the library as it is decision that need to be made by the user and needs might be pretty different for all of us)
Essentially it's this:
class MyBot(token: String, chatId: Long, processor: CommunicationProcessor) extends TelegramBot with Polling {
override val client: RequestHandler[Future] = new ScalajHttpClient(token)
override def receiveMessage(msg: Message): Future[Unit] =
if (msg.source != chatId) {
println(s"Received a message from a wrong chat: id=${msg.source}, title=${msg.chat.title.getOrElse("N/A")}")
Future.successful(())
} else
msg.text match {
case Some(text) =>
println(s"Incoming message: source=telegram, msg=$text")
Future(processor.process(text))
case None =>
Future.successful(())
}
}
And then in Main:
val bot = new MyBot(config.telegramToken, config.telegramMainChatId, processor)
val eol = bot.run()
scala.sys.addShutdownHook {
bot.shutdown()
}
we won't retry inside the library as it is decision that need to be made by the user and needs might be pretty different for all of us
Yeah, that's true, but it might be quite common use, so maybe it can be set as an input parameter when constructing the instance? Like, no reconnects by default, but the caller can also indicate the reconnects are needed (probably a specific interval or some backoff)
@ex0ns, do you by any chance have any thoughts regarding the above?
Hello
Sorry I don't have a proper solution as of now (one that I'm liking anyway), and I'm pretty busy, I would definitely encourage you to propose an implementation if you feel like it, otherwise it might have to wait on my side and I might tackle it when I have more room for it