Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Entwicklung
  4. [Hilfe] parllele asynchrone lese/schreibe HTTP Requests (Adapterentwicklung)

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    17
    1
    3.2k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    1.1k

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.4k

[Hilfe] parllele asynchrone lese/schreibe HTTP Requests (Adapterentwicklung)

Geplant Angeheftet Gesperrt Verschoben Entwicklung
10 Beiträge 4 Kommentatoren 683 Aufrufe
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • StuebiS Offline
    StuebiS Offline
    Stuebi
    schrieb am zuletzt editiert von
    #1

    Ich brauche mal Eure Hilfe. JavaScript ist ziemlich neu für mich! Ich versuche gerade für die Alarmanlage Lupusec einen Adapter zu entwickeln. Für das Lesen und Setzen von Status (Plural?) bietet der Hersteller mehrere APIs an, die ich über HTTP Requests nutzen kann. D.h. es gibt ca. 4 Lese APIs und 2 APIs zum schreiben.

    Lesen:

    Alle 15 Sekunden werden alle 4 Lese APIs (asynchroner HTTP Request) aufgerufen. Bei einer Statusänderung durch die APIs wird der Status in den entsprechenden ioBroker Objekten mit ack = true angepasst.

    Schreiben:

    Wird der Status in einem ioBroker Objekt geändert, werden in adapter.on("stateChange", function (id, state) die entsprechenden APIs (asynchronen HTTP Requests) zum Ändern des Status in der Alarmanlage aufgerufen.

    1. Wenn ein Zugriff einer API beim lesen länger als 15 Sekunden benötigt (asyncr. http request), wird der Lesezugriff nochmals im setInterval gestartet, bevor der vorherige Zugriff abgearbeitet ist. Damit kann ich noch leben.

    2. Die 4 Lesezugriffe (4 asynchrone http requests) laufen parallel. Die Alarmanlage, scheint damit kein Problem zu haben. Auch damit kann ich leben. Ist vielleicht auch besser als das sequentielle abarbeiten der http requests (mir würde da als sequentielle Lösung nur der Weg von Request in Requests über callbacks einfallen oder die Nutzung von Probmise)

    3. Jetzt das eigentliche Problem bzw. Hauptproblem. Es ist nicht unwahrscheinlich, dass der Lesezugriff für ein Status noch läuft und in dem Moment der Status in einem ioBroker Objekt geändert wird. Die Update API wird in adapter.on("stateChange", function (id, state) wird gestartet. Jetzt kann es sein, das der laufende Read Prozess den gesetzten ioBroker Status des Benutzers überschreibt. Damit kommt es zu einem falschen Zustand.

    Bsp.

    ioBroker-Stauts-abc = 0

    • Read API (Process 1) startet

    • Benutzer ändert ioBroker-Stauts-abc = 1 (ack = false)

    • Write API (Process 2) startet in adapter.on("stateChange", function (id, state)

    • Read API (Process 1) ändert Status ioBroker-Stauts-abc auf 0 und ack = true, (der Wert war vorher 1 durch den Benutzer mit ack = false gesetzt und überschrieben mit Wert 0 aus der Alarmanlage)

    • Read API (Process 1) beendet sich

    • Wirte API (Process 2) ändert Status in der Alarmanlage auf 1

    • Wirte API (Process 2) beendet sich

    • Read API (Process 3) startet

    • Read API (Process 3) ändert Status ioBroker-Stauts-abc auf 1 und ack = true, da ioBroker-Stauts-abc ja 0 ist (ack bleibt true).

    • Read API (Process 3) beendet sich
      Wenn es gut läuft sieht es so aus:

    ioBroker-Stauts-abc = 0

    • Read API (Process 1) startet

    • Read API (Process 1) beendet sich, da nichts zu ändern ist (Wert in Alarmanlage auch 0)

    • Benutzer ändert ioBroker-Stauts-abc = 1 (ack = false)

    • Write API (Process 2) startet in adapter.on("stateChange", function (id, state)

    • Wirte API (Process 2) ändert Status in der Alarmanlage auf 1

    • Wirte API (Process 2) beendet sich

    • Read API (Process 3) startet

    • Read API (Process 3) ändert Status ioBroker-Stauts-abc auf 1 und ack = true, da vorher 1 und ack = false (Wert 1 aus Alarmanlage ist gelesen).

    • Read API (Process 3) beendet sich

    Hat jemand eine Idee wie ich das verhindern kann?

    https://github.com/schmupu/ioBroker.lupusec

    ioBroker auf Synology DS216+II im Docker Container

    1 Antwort Letzte Antwort
    0
    • AlCalzoneA Offline
      AlCalzoneA Offline
      AlCalzone
      Developer
      schrieb am zuletzt editiert von
      #2

      > Es ist nicht unwahrscheinlich, dass der Lesezugriff für ein Status noch läuft und in dem Moment der Status in einem ioBroker Objekt geändert wird. Die Update API wird in adapter.on("stateChange", function (id, state) wird gestartet. Jetzt kann es sein, das der laufende Read Prozess den gesetzten ioBroker Status des Benutzers überschreibt. Damit kommt es zu einem falschen Zustand.

      Ohne jetzt im Detail auf den tatsächlichen Ablauf einzugehen, sehe ich grundsätzlich zwei Möglichkeiten, die beide auf einer Boolean-Status-Variable basieren:

      1. Beschäftigt-Variable "busy" => 1. Prozess hat Vorrang:

      Beim Start eines länger dauernden Prozesses (der nicht mehrfach laufen soll) wird diese auf true gesetzt, zum Abschluss auf false.

      Wenn der Prozess (Instanz 2) gestartet werden sollte, aber busy = true ist, den Prozess nicht starten.

      2. Abbrechen-Variable "cancel", am besten in Kombination mit der Beschäftigt-Variablen => letzter Prozess hat Vorrang:

      Beim Start einer weiteren Instanz des Prozesses wird (sofern busy = true ist), wird cancel auf true gesetzt. Der laufende Prozess prüft in regelmäßigen Abständen ob er abgebrochen werden soll, macht dann nicht weiter und setzt cancel auf false.

      Ganz und Überschneidungsfrei wäre es, wenn du dir alle laufenden Prozesse in einer Liste merkst und somit jedem laufendem Prozess getrennt den Abbrechen-Befehl senden kannst.

      Hier ein Beispiel aus der .NET-Welt, wie das mit einem sogenannten CancellationToken realisiert werden kann: http://kean.github.io/post/cancellation-token

      Warum `sudo` böse ist: https://forum.iobroker.net/post/17109

      1 Antwort Letzte Antwort
      0
      • ruhr70R Offline
        ruhr70R Offline
        ruhr70
        schrieb am zuletzt editiert von
        #3

        @tstueben:

        3. Jetzt das eigentliche Problem bzw. Hauptproblem. Es ist nicht unwahrscheinlich, dass der Lesezugriff für ein Status noch läuft und in dem Moment der Status in einem ioBroker Objekt geändert wird. Die Update API wird in adapter.on("stateChange", function (id, state) wird gestartet. Jetzt kann es sein, das der laufende Read Prozess den gesetzten ioBroker Status des Benutzers überschreibt. Damit kommt es zu einem falschen Zustand. `

        Könnte man nicht auch mit Zeitstempeln arbeiten und diese Vergleichen?

        Wenn der Wert im DP aktueller ist, als zum Start des Requests…

        Adapter: Fritzbox, Unify Circuit
        Skripte: dynamic hue, Bluetooth Scan, Multi-Ereignisliste

        1 Antwort Letzte Antwort
        0
        • apollon77A Online
          apollon77A Online
          apollon77
          schrieb am zuletzt editiert von
          #4

          Zu 1.) kein Intervall nehmen sondern mit setTimeout arbeiten der immer am Ende des letzten der reads (wenn Ergebnis da ist) auf 15s später gesetzt wird

          Zu 3.) ich würde mir im Adapter merken was der letzte wert war und bei einen read nur dann schreiben wenn der Wert anders ist. Das reduziert Schöntal dein Problem.

          Die andere frage ist wann der Wert als „bestätigt gesetzt“ angesehen werden kann. Direkt wenn Update api „ok“ sagt oder erst wenn Du danach nochmal gelesen hast und der Wert dann geändert zurückkommt.

          Mit der Timeout Idee von oben (Timeout „handle“ in Variable merken und auf null setzen wenn Timeout getriggert wurde) siehst du ob gerade ein read läuft (Timeout variable ist null) oder nicht (!=null) und kannst darauf reagieren und ggf ein Boolean flag setzen was ein read Ergebnis ignoriert.

          Kam das einigermaßen verständlich rüber?

          Beitrag hat geholfen? Votet rechts unten im Beitrag :-) https://paypal.me/Apollon77 / https://github.com/sponsors/Apollon77

          • Debug-Log für Instanz einschalten? Admin -> Instanzen -> Expertenmodus -> Instanz aufklappen - Loglevel ändern
          • Logfiles auf Platte /opt/iobroker/log/… nutzen, Admin schneidet Zeilen ab
          1 Antwort Letzte Antwort
          0
          • StuebiS Offline
            StuebiS Offline
            Stuebi
            schrieb am zuletzt editiert von
            #5

            @apollon77:

            Zu 1.) kein Intervall nehmen sondern mit setTimeout arbeiten der immer am Ende des letzten der reads (wenn Ergebnis da ist) auf 15s später gesetzt wird `

            Gute Idee. Da die Read Funktion durch den HTTP Request asynchron ist, muss ich den setTimout im HTTP Request setzten und dort die Read Funktion wieder aufrufen. Ich hoffe ich habe da keinen Denkfehler.

            @apollon77:

            Zu 3.) ich würde mir im Adapter merken was der letzte wert war und bei einen read nur dann schreiben wenn der Wert anders ist. Das reduziert Schöntal dein Problem. `

            Ja, genau so mache ich es. Ich ändere den Wert nur wenn er anders als der vorherige ist ode wenn ack == false.

            @apollon77:

            Die andere frage ist wann der Wert als „bestätigt gesetzt“ angesehen werden kann. Direkt wenn Update api „ok“ sagt oder erst wenn Du danach nochmal gelesen hast und der Wert dann geändert zurückkommt.

            Mit der Timeout Idee von oben (Timeout „handle“ in Variable merken und auf null setzen wenn Timeout getriggert wurde) siehst du ob gerade ein read läuft (Timeout variable ist null) oder nicht (!=null) und kannst darauf reagieren und ggf ein Boolean flag setzen was ein read Ergebnis ignoriert.

            Kam das einigermaßen verständlich rüber? `

            das kam verständlich rüber. Da muss ich mal schauen, wie ich das am besten umsetze. Ich muss ja den Update solange "parken", bis der aktuelle Read durch ist!

            Momentan habe ich die Lösung von @ruhr70 mit dem Timestamp übernommen.

            ioBroker auf Synology DS216+II im Docker Container

            1 Antwort Letzte Antwort
            0
            • apollon77A Online
              apollon77A Online
              apollon77
              schrieb am zuletzt editiert von
              #6

              Naja Update parken musst du nicht. Mach ne variable „ignoriere_read“ die du setzt sobald du den update schickst der beim read Ergebnis dafür sorgt das es einfach ignoriert wird.

              Ich kann mit das nach dem Urlaub wenn ich wieder Laptop gab gern nochmal ansehen. Wenn die Lösungsidee von Ruhr aber tut ist alles bestens ;-)

              Beitrag hat geholfen? Votet rechts unten im Beitrag :-) https://paypal.me/Apollon77 / https://github.com/sponsors/Apollon77

              • Debug-Log für Instanz einschalten? Admin -> Instanzen -> Expertenmodus -> Instanz aufklappen - Loglevel ändern
              • Logfiles auf Platte /opt/iobroker/log/… nutzen, Admin schneidet Zeilen ab
              1 Antwort Letzte Antwort
              0
              • StuebiS Offline
                StuebiS Offline
                Stuebi
                schrieb am zuletzt editiert von
                #7

                @apollon77:

                Naja Update parken musst du nicht. Mach ne variable „ignoriere_read“ die du setzt sobald du den update schickst der beim read Ergebnis dafür sorgt das es einfach ignoriert wird.

                Ich kann mit das nach dem Urlaub wenn ich wieder Laptop gab gern nochmal ansehen. Wenn die Lösungsidee von Ruhr aber tut ist alles bestens ;-) `

                das wäre super!!

                jetzt habe ich alles auf setTimeout umgestellt und finde nach einer Weile einen "heap out of memory" Fehler im Log und der Adapter restarted. Ich gehe davon aus, dass der Fehler in der Funktion read() liegt. Was mache ich verkehrt? Wie kann ich mit setTimout "mich selber" immer wieder aufrufen?

                  function read() {
                
                    var options = {
                      url: self.getURL(urlDeviceListGet),
                      rejectUnauthorized: false,
                      headers: {
                        "Authorization": self.auth
                      }
                    };
                
                    // GetRequest(options, callback);
                    GetRequest(options, function(error, data) {
                
                      parse(error, data); // hier wird data verarbeitet
                
                      setTimeout(read, self.pollsec * 1000);
                
                    });
                
                  }
                
                 function GetRequest(options, callback) {
                
                  request.get(options,
                
                    function(error, response, body) {
                
                      if (error || response.statusCode !== 200) {
                
                        return callback(error);
                
                      } else if (body) {
                
                        try {
                
                	 // Sourcecode
                
                          if (callback) {
                
                            callback(null, body);
                
                          } 
                
                        } catch (e) {
                
                        }
                
                      }
                
                    });
                
                }
                
                

                ioBroker auf Synology DS216+II im Docker Container

                1 Antwort Letzte Antwort
                0
                • StuebiS Offline
                  StuebiS Offline
                  Stuebi
                  schrieb am zuletzt editiert von
                  #8

                  @tstueben:

                  @apollon77:

                  Naja Update parken musst du nicht. Mach ne variable „ignoriere_read“ die du setzt sobald du den update schickst der beim read Ergebnis dafür sorgt das es einfach ignoriert wird.

                  Ich kann mit das nach dem Urlaub wenn ich wieder Laptop gab gern nochmal ansehen. Wenn die Lösungsidee von Ruhr aber tut ist alles bestens ;-) `

                  das wäre super!!

                  jetzt habe ich alles auf setTimeout umgestellt und finde nach einer Weile einen "heap out of memory" Fehler im Log und der Adapter restarted. Ich gehe davon aus, dass der Fehler in der Funktion read() liegt. Was mache ich verkehrt? Wie kann ich mit setTimout "mich selber" immer wieder aufrufen?

                    function read() {
                  
                      var options = {
                        url: self.getURL(urlDeviceListGet),
                        rejectUnauthorized: false,
                        headers: {
                          "Authorization": self.auth
                        }
                      };
                  
                      // GetRequest(options, callback);
                      GetRequest(options, function(error, data) {
                  
                        parse(error, data); // hier wird data verarbeitet
                        
                        setTimeout(read, self.pollsec * 1000);
                  
                      });
                  
                    }
                  
                   function GetRequest(options, callback) {
                  
                    request.get(options,
                  
                      function(error, response, body) {
                  
                        if (error || response.statusCode !== 200) {
                  
                          return callback(error);
                  
                        } else if (body) {
                  
                          try {
                  
                  	 // Sourcecode
                  	 
                            if (callback) {
                  
                              callback(null, body);
                  
                            } 
                  
                          } catch (e) {
                  
                          }
                  
                        }
                  
                      });
                  
                  }
                  
                  ```` `  
                  

                  Fehler gefunden! Ich hatte an einer Stelle setInterval statt setTimeout benutzt.

                  ioBroker auf Synology DS216+II im Docker Container

                  1 Antwort Letzte Antwort
                  0
                  • StuebiS Offline
                    StuebiS Offline
                    Stuebi
                    schrieb am zuletzt editiert von
                    #9

                    @apollon77:

                    ;-) `
                    Eine Frage hätte ich aber noch zum dem setTimeout. Wenn sich die Funktion mit dem setTimeout immer selber in den aufgerufenen asynchronen Funktionen aufrufe, landen die Aufrufe nicht alle auf dem Stack. Und irgendwann geht dann nichts mehr?

                    Ist es sinnvoll vor dem nächsten handle = setTimeout, den vorherigen mit clearTimeout(handle) zu löschen?

                    ioBroker auf Synology DS216+II im Docker Container

                    1 Antwort Letzte Antwort
                    0
                    • apollon77A Online
                      apollon77A Online
                      apollon77
                      schrieb am zuletzt editiert von
                      #10

                      Bei setTimeout wird es einmalig ausgeführt. Dann ist es ja weg und die zurückgegebene id ungültig.

                      Diese zurückgegebene id nutzt du nur um den Timeout vorzeitig abzubrechen (oder als Trick um zu sehen ob er schon gefeuert wurde oder nicht)

                      Beitrag hat geholfen? Votet rechts unten im Beitrag :-) https://paypal.me/Apollon77 / https://github.com/sponsors/Apollon77

                      • Debug-Log für Instanz einschalten? Admin -> Instanzen -> Expertenmodus -> Instanz aufklappen - Loglevel ändern
                      • Logfiles auf Platte /opt/iobroker/log/… nutzen, Admin schneidet Zeilen ab
                      1 Antwort Letzte Antwort
                      0
                      Antworten
                      • In einem neuen Thema antworten
                      Anmelden zum Antworten
                      • Älteste zuerst
                      • Neuste zuerst
                      • Meiste Stimmen


                      Support us

                      ioBroker
                      Community Adapters
                      Donate

                      633

                      Online

                      32.7k

                      Benutzer

                      82.3k

                      Themen

                      1.3m

                      Beiträge
                      Community
                      Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                      ioBroker Community 2014-2025
                      logo
                      • Anmelden

                      • Du hast noch kein Konto? Registrieren

                      • Anmelden oder registrieren, um zu suchen
                      • Erster Beitrag
                        Letzter Beitrag
                      0
                      • Home
                      • Aktuell
                      • Tags
                      • Ungelesen 0
                      • Kategorien
                      • Unreplied
                      • Beliebt
                      • GitHub
                      • Docu
                      • Hilfe