Java Telegram-API: Was tun bei Exception?

CyborgBeta

Captain
Registriert
Jan. 2021
Beiträge
3.177
Hi,

Java:
    // String bot_name = "...";
    String bot_token = "...";

    // Create your bot passing the token received from @BotFather
    TelegramBot bot = new TelegramBot(bot_token);

    // Register for updates
    bot.setUpdatesListener(
        updates -> {
          for (Update update : updates) {
            if (update.message() != null) {
              String text = update.message().text();
              if (text != null
                  && !text.startsWith("Prefix2:")
                  && text.toLowerCase(Locale.ROOT).startsWith("Prefix1: ")) {
                try {
                  String chatAnswer = "Prefix2: " + getAnswer(text.substring(9));
                  long chatId = update.message().chat().id();
                  SendResponse response = bot.execute(new SendMessage(chatId, chatAnswer));
                  System.out.println("Question   = " + text);
                  System.out.println("Answer     = " + chatAnswer);
                  System.out.println("Response   = " + response.isOk());
                } catch (Exception e) {
                  throw new RuntimeException(e);
                }
              }
            }
          }
          // return id of last processed update or confirm them all
          return UpdatesListener.CONFIRMED_UPDATES_ALL;
          // Create Exception Handler
        },
        e -> {
          if (e.response() != null) {
            // got bad response from telegram
            System.out.println(e.response().errorCode() + ": " + e.response().description());
          }
          throw new RuntimeException(e);
        });

mein Bot lauscht auf "Prefix1" und antwortet dann mit "Prefix2" ... so weit, so gut. Von Zeit zu Zeit kann es passieren (zum Beispiel nach einem Tag), dass in Zeile 38 eine Exception geworfen wird, und ich die Anwendung neu starten muss, zum Beispiel, weil i-was mit dem Telegram-Server ist ...

Wie sollte ich korrekt damit umgehen? Vielleicht eine Minute warten, und dann maximal 3 Neustarts?

Danke
 
Lösung
Java:
  public static void main(String[] args) {
    // String bot_name = "...";
    String bot_token = "...";

    // Create your bot passing the token received from @BotFather
    TelegramBot bot = new TelegramBot(bot_token);

    // Register for updates
    bot.setUpdatesListener(
        updates -> {
          for (Update update : updates) {
            if (update.message() != null) {
              String text = update.message().text();
              if (text != null
                  && !text.startsWith("ChatGPT:")
                  && text.toLowerCase(Locale.ROOT).startsWith("frage: ")) {
                try {
                  String chatGptAnswer = "ChatGPT: " + getChatGptAnswerMulti(text);
                  long chatId =...
tollertyp schrieb:
Doofe Frage: Zwangstrennung kann da nicht der Grund sein?
Wenn ich dann einen Restart mache, funktioniert die Anwendung direkt wieder... und meine eigene IP ändert sich nicht...
 
Ich würde erst mal schauen, was da konkret für Exceptions auflaufen und ob man wenigstens auf ein paar davon vor Ort "beheben" oder einfach ignorieren kann.
 
  • Gefällt mir
Reaktionen: SuperCube, CyborgBeta und Der Lord
Hab mal in die Logs geschaut und seit heute Morgen ist keine aufgetreten. Ich melde mich später noch mal, wenn eine auftritt...
 
Zuletzt bearbeitet: (+Link)
  • Gefällt mir
Reaktionen: CyborgBeta
Bitte nicht unterstellen, ich würde den stack trace nicht kennen ... Wie gesagt, ich muss erst warten, bis die nächste "echte" Exception auftritt, dann melde ich mich noch mal.
 
CyborgBeta schrieb:
Bitte nicht unterstellen, ich würde den stack trace nicht kennen
nein "wir" kennen ihn nicht - wie soll man da irgendeinen Hinweise geben können zu den Apis oder der eigene Art Dinge zu implementieren?

Objectlifecycle is a Bitch - zB ist es manchmal sinnvoll sich zu entscheiden

A) Objekte (Verbindungen usw.) immer auf und zuzumachen (und zu dereferenzieren ) oder

B) diese Dauernd zu behalten aber dann eben deren Vitalität vor der Nutzung zu prüfen bzw. eben
eine bestimmte Exception abzufangen um die zugemachte Verbindung/abgelaufenen Sessiontoken dann neu zu machen

Ahoi D.
 
  • Gefällt mir
Reaktionen: SuperCube und Der Lord
Zurzeit ist (a) der Fall. Es wird dauernd gelauscht ... Aber von Zeit zu Zeit kann es eben sein, dass die Verbindung abbricht. Dann schaue ich auf dem Server nach, was los ist, und starte die Anwendung/den Bot eben neu. Ich kann den Stacktrace eben erst sehen, wenn "in echt" eine Exception aufgetreten ist.

Es geht übrigens um diese Lib/API: https://github.com/pengrad/java-telegram-bot-api

(diese basiert u. a. auf https://github.com/square/okhttp)

Ich bin da noch nicht tief eingestiegen, aber die TelegramException ist im Prinzip eine Erweiterung einer normalen Exception, und kann damit ja vieles sein: https://github.com/pengrad/java-tel...om/pengrad/telegrambot/TelegramException.java
 
Dein Exception-Handler sollte keine Exception werfen. Er wird hier oder hier aufgerufen und wenn er eine Exception wirft, geht's halt anschließend nicht mit sleep() und neuem Request weiter.

Und Dein Response-Handler sollte bei einem Fehler die letzte erfolgreich verarbeitete Update-ID bzw. UpdatesListener.CONFIRMED_UPDATES_NONE zurückgeben.

An den Interface-Methoden, die Deine Handler implementieren, steht übrigens kein throws Exception dran, und das mit einer unchecked Exception zu umgehen, ist keine gute Idee. Du kannst nicht erwarten, dass der Caller die fängt und was sinnvolles tut.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: CyborgBeta
Also ist Zeile 24 (das Umverpacken und Weiterreichen der Exception) und Zeile 30 falsch?

Also kommt die Exception dann gar nicht von Telegram, sondern von meinem getAnswer-Aufruf? Das könnte Sinn ergeben.
 
... nunja man Baut Exceptionhandeler um einen logischen Codeblock um sinnvoll zu interagieren

A) manchmal nur Loginfos auszugeben
B) Aktionen anders/neu zu Machen usw.


Die sich entwickelnde ReRaise Kultur mit Stacktracetecpichen
ist für mich nur ein "verkapptes Dauer-Goto"-Desaster der heutigen Zeit
und verstopft den Blick aufs Problem zunehmend.

Nicht so:
Hinweis: konnte Parameter XY nicht bestimmen und benutze Wert 123 als Fallback

Sondern das ist der Stand:
Exception <hier ausfüllen> + 30 weitere Zeilen Stacktrace


Woher kommt denn der Rohcode?
Ergänzung ()

bin ja nur DB Entwickler und meine javaprojekte liegen 20 Jahre zurück

Code:
text.toLowerCase(Locale.ROOT).startsWith("Prefix1: "))

wie soll sich im gelowerten String ein Casesensitiver String finden?
Ergänzung ()

anstelle
Code:
getAnswer()

als alter Mann würde ich zB

Code:
bot.getAnswer()

schreiben - da muss ich nicht extra nachgrübeln was so passiert
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: SuperCube, CyborgBeta und Der Lord
dms schrieb:
wie soll sich im gelowerten String ein Casesensitiver String finden?

Haste wahr, "Prefix1" und "Prefix2" waren nur Schlüsselwörter, die ich nachträglich eingebaut hatte, um sie im Forum zu posten.

In echt stehen da lowercase Konstanten.

Ich habe das jetzt mal umgebaut, sodass die Anwendung theoretisch nicht beendet werden sollte, wenn ein Fehler auftritt:

Java:
    // Register for updates
    bot.setUpdatesListener(
        updates -> {
          for (Update update : updates) {
            if (update.message() != null) {
              String text = update.message().text();
              if (text != null
                  && !text.startsWith("ChatGPT:")
                  && text.toLowerCase(Locale.ROOT).startsWith("frage: ")) {
                try {
                  String chatGptAnswer = "ChatGPT: " + getChatGptAnswer(text.substring(7));
                  long chatId = update.message().chat().id();
                  SendResponse response = bot.execute(new SendMessage(chatId, chatGptAnswer));
                  System.out.println("Question   = " + text);
                  System.out.println("Answer     = " + chatGptAnswer);
                  System.out.println("Response   = " + response.isOk());
                } catch (Exception e) {
                  System.out.println(e.getMessage());
                }
              }
            }
          }
          // Confirm them all
          return UpdatesListener.CONFIRMED_UPDATES_ALL;
        },
        e -> {
          System.out.println(e.getMessage());
          if (e.response() != null) {
            // got bad response from telegram
            System.out.println(e.response().errorCode() + ": " + e.response().description());
          }
        });

Mal schauen, wie es sich dann verhält.

Das return UpdatesListener.CONFIRMED_UPDATES_ALL; sollte doch nur eine Lesebestätigung senden, imho.
 
CyborgBeta schrieb:
Also ist Zeile 24 (das Umverpacken und Weiterreichen der Exception) und Zeile 30 falsch?
Ja. Führe vor dem Update-Loop eine Variable var lastConfirmedUpdate = UpdatesListener.CONFIRMED_UPDATES_NONE; ein und aktualisiere sie am Ende des Loop-Blocks auf die Update-ID. Ersetze Zeile 24 und 30 durch return lastConfirmedUpdate;.

Den Exception-Handler kannst Du weglassen, denn ohne macht der Bot im Prinzip das gleiche, in einem Fall aber besser (wenn es keine Message sondern eine Cause gibt).

CyborgBeta schrieb:
Also kommt die Exception dann gar nicht von Telegram, sondern von meinem getAnswer-Aufruf? Das könnte Sinn ergeben.
Kann sein, muss aber nicht. Egal welcher Handler eine Exception wirft, es geht dann nicht weiter.

Allgemein sollte das recht robust laufen und keine Updates verloren gehen, wenn Du das mit der letzten Update-ID richtig machst und keine Exceptions wirfst.
 
  • Gefällt mir
Reaktionen: SuperCube und CyborgBeta
@H4110 Danke, ich habe das so wie vorgeschlagen umgeschrieben, und bis jetzt läuft es stabil/robust:

Java:
    // Register for updates
    bot.setUpdatesListener(
        updates -> {
          int lastConfirmedUpdate = UpdatesListener.CONFIRMED_UPDATES_NONE;
          for (Update update : updates) {
            if (update.message() != null) {
              String text = update.message().text();
              if (text != null
                  && !text.startsWith("ChatGPT:")
                  && text.toLowerCase(Locale.ROOT).startsWith("frage: ")) {
                try {
                  String chatGptAnswer = "ChatGPT: " + getChatGptAnswer(text.substring(7));
                  long chatId = update.message().chat().id();
                  SendResponse response = bot.execute(new SendMessage(chatId, chatGptAnswer));
                  System.out.println("Question   = " + text);
                  System.out.println("Answer     = " + chatGptAnswer);
                  System.out.println("Response   = " + response.isOk());
                  lastConfirmedUpdate = update.updateId();
                } catch (Exception e) {
                  System.out.println(e.getMessage());
                }
              }
            }
          }
          // Confirm last update. Important!
          return lastConfirmedUpdate;
        },
        e -> {
          System.out.println(e.getMessage());
          if (e.response() != null) {
            // Bad response from telegram
            System.out.println(e.response().errorCode() + ": " + e.response().description());
          }
          // Ignore and continue
        });
 
lastConfirmedUpdate = update.updateId(); muss ganz ans Ende hinter die if für den Fall, dass bei den letzten Updates die Bedingungen nicht zutreffen. Ansonsten würden die immer wieder kommen, bis es weitere Updates gibt und beim letzten alle Bedingungen zutreffen.

In den Catch-Block muss auch return lastConfirmedUpdate;, ansonsten fallen die gescheiterten unter den Tisch. Falls das okay ist, kannst Du auch bei return UpdatesListener.CONFIRMED_UPDATES_ALL; bleiben.

Hier siehst Du übrigens, was mit der Update-ID passiert: basierend darauf wird der Offset für den nächsten API-Request gesetzt, so dass nicht verarbeitete Updates nochmal kommen.
Ergänzung ()

Hmm, am Ende des Handlers kann man eigentlich immer UpdatesListener.CONFIRMED_UPDATES_ALL zurückgeben - haben dann ja alle geklappt. Aber im Catch-Block muss es return lastConfirmedUpdate; sein, wenn das Update nicht unter den Tisch fallen und wiederholt werden soll.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: SuperCube und Der Lord
Mist, sag das doch etwas eher. ;) Gut, dass jetzt gerade noch kein Fehler aufgetreten ist...
 
Java:
  public static void main(String[] args) {
    // String bot_name = "...";
    String bot_token = "...";

    // Create your bot passing the token received from @BotFather
    TelegramBot bot = new TelegramBot(bot_token);

    // Register for updates
    bot.setUpdatesListener(
        updates -> {
          for (Update update : updates) {
            if (update.message() != null) {
              String text = update.message().text();
              if (text != null
                  && !text.startsWith("ChatGPT:")
                  && text.toLowerCase(Locale.ROOT).startsWith("frage: ")) {
                try {
                  String chatGptAnswer = "ChatGPT: " + getChatGptAnswerMulti(text);
                  long chatId = update.message().chat().id();
                  SendResponse response = bot.execute(new SendMessage(chatId, chatGptAnswer));
                  System.out.println("Question   = " + text);
                  System.out.println("Answer     = " + chatGptAnswer);
                  System.out.println("Response   = " + response.isOk());
                } catch (Exception e) {
                  System.out.println(e.getMessage());
                }
              }
            }
          }
          // Confirm all updates
          return UpdatesListener.CONFIRMED_UPDATES_ALL;
        },
        e -> {
          System.out.println(e.getMessage());
          if (e.response() != null) {
            // Bad response from telegram
            System.out.println(e.response().errorCode() + ": " + e.response().description());
          }
          // Ignore and continue
        });
  }

Läuft jetzt stabil, auch wenn getChatGptAnswerMulti eine Exception hochwuppt.

Das throw new RuntimeException(e); war keine gute Idee gewesen ...

Wer möchte jetzt als beste Antwort ausgezeichnet werden?
 
Zurück
Oben