Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Long running Rest API Call mit THTTPClient (https://www.delphipraxis.net/196881-long-running-rest-api-call-mit-thttpclient.html)

Christoph Schneider 27. Jun 2018 10:20

Long running Rest API Call mit THTTPClient
 
Ich benötige für einen Event von einem Rest-Server einen long running HTTP-Request.

Wie macht man das sauber mit Delphi Board mitteln?

Meine aktuelle Lösung läuft zwar nach einigem Probieren. Der Stop des Request geht leider nur auf die harte Tour mit einem Thread.Terminate und hinterlässt dann als Folge unschöne Memory Leaks.

Delphi-Quellcode:
type
  TMyRestAPI = class
  private
    fClient: THTTPClient;
    fStream: TMemoryStream;
    fReadPos: Int64;
    fOnReceiveData: procedure(const data: string) of object;
    procedure OnRecData(const Sender: TObject; AContentLength: Int64;
      AReadCount: Int64; var Abort: Boolean);
  public
    procedure StartRequest(const URL: string);
    procedure StopRequest;
  end;

procedure TMyRestAPI.StartRequest(const URL: string);
begin
  fClient := THTTPClient.Create;
  fClient.HandleRedirects := true;
  fClient.Accept := 'text/event-stream';
  fClient.OnReceiveData := OnRecData;
  fStream := TMemoryStream.Create;
  fReadPos := 0;
  fThread := TThread.CreateAnonymousThread(
    procedure
    begin
      fClient.Get(URL, fStream);
    end);
  fThread.Start;
end;

procedure TMyRestAPI.OnRecData(const Sender: TObject; AContentLength: Int64;
  AReadCount: Int64; var Abort: Boolean);
var
  ss: TStringStream;
  resp: string;
begin
  ss := TStringStream.Create;
  try
    fStream.Position := readPos;
    ss.CopyFrom(fStream, AReadCount - fReadPos);
    fOnReceiveData(ss.DataString);
    fReadPos := AReadCount;
  finally
    ss.Free;
  end;
end;

procedure TMyRestAPI.StopRequest;
begin
  fThread.Terminate;
  fClient.Free;
  fStream.Free;
end;
Da ich den Request alle paar Stunden repetitiv abbrechen muss um anschliessend mit einem neuen Token zu restarten, suche ich eine bessere Lösung.
Bei Verwendung der Asynchronen Calls mit BeginExecute/BeginGet lässt sich der laufende Request leider auch nur stoppen, wenn Daten vom Server empfangen werden.
Gerade dies ist aber bei einem long running rest API Call über längere Zeit hinweg nicht der Fall und ich fand kein Weg, den asynchrone Request zu einem beliebigen Zeitpunkt zu stoppen.

Delphi-Quellcode:
Async := fClient.BeginGet(URL);
Meine Lösung sollte unter Firemonkey auf allen Plattformen laufen, dass wäre mindestens dass Ziel!

TiGü 27. Jun 2018 10:29

AW: Long running Rest API Call mit THTTPClient
 
Hast du dich bewusst gegen die REST-Komponenten (TRESTRequest, TRESTClient,TRESTResponse) entschieden?
http://docwiki.embarcadero.com/RADSt...ientbibliothek

(Was völlig okay wäre, um klein und schlank zu bleiben, aber ich wollte trotzdem fragen.)

Der schöne Günther 27. Jun 2018 10:38

AW: Long running Rest API Call mit THTTPClient
 
Siehe auch:
https://www.delphipraxis.net/192625-...erringern.html

TiGü 27. Jun 2018 12:12

AW: Long running Rest API Call mit THTTPClient
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1405936)

(an den Thread musste ich auch denken...ist das schon wieder so lange her? :shock:)

Der schöne Günther 27. Jun 2018 12:33

AW: Long running Rest API Call mit THTTPClient
 
So etwas bringt mich auch immer wieder aus der Fassung. Das Problem liegt bei mir übrigens immer noch in der Schublade, die Timeouts sind bis heute immer noch drin :roteyes:

TiGü 27. Jun 2018 12:56

AW: Long running Rest API Call mit THTTPClient
 
Aber das liese sich doch mit den Intercepten der Windows-Funktionen doch problemlos umgehen.

Christoph Schneider 27. Jun 2018 18:02

AW: Long running Rest API Call mit THTTPClient
 
Die Verwendung von Timeouts ist aus meiner Sicht keine praktikable Lösung für mein Problem. Ich müsste ein kurzes Timeout (1 Sek) wählen, um die Anforderung für eine gute Reaktion beim Beenden einzuhalten.
In der Folge möchte ich aber nicht alle Sekunden den Http-Request wieder neu starten müssen nur weil ich bei Beendigung des Programm nicht länger als eine Sekunde warten darf.

Ich brauche ich den long running Calls genau dafür, dass ich über längere Zeit den Stream offen halten kann und auf Ereignisse vom Server reagieren kann.
Klar könnte man dies theoretisch auch mit einem Polling machen, bei dem alle Sekunden ein Get-Request an den Server gesandt wird. Nur bedeutet dies enorm viel mehr Traffic, den ich vermeiden will.

Daher suche ich an einer Lösung, wie ich ein laufenden HTTP-Request bei Programm-Ende oder auf nach User-Interaktion sauber stoppen kann.

Die Delphi Rest-Komponenten setzt ja auch auf der THTTPClient (In TRESTHTTP ist FHTTPClient auch System.Net.HTTPClient.THTTPClient) und ich dachte mir, je näher ich an der Basis-Komponente bin, desto besser kann ich deren Verhalten steuern. Mit der TNetHTTPClient und Client.Asynchronous := true habe ich es bereits probiert. Hier kann ich den Request auch nicht schliessen, wenn keine Daten vom Server empfangen werden.

Wie machen denn andere long running rest API Calls? Und mit long running meine ich den Request eine Stunde oder länger offen zu halten und bei Bedarf wieder schliessen zu können.

@TiGü: Wie würdest Du das angehen mit Interceptoren vor und nach der WinApi-Funktion? Eigentlich wollte ich den HTTP-Requestnicht selber für alle Plattformen (mindestens Mac OS und Win32/64) implementieren aber vielleicht läuft es am Schluss doch auf eine solche Lösung raus.

TiGü 27. Jun 2018 18:25

AW: Long running Rest API Call mit THTTPClient
 
Meine Idee mit den Interceptoren bezog sich ja auf das Timeout-Problem vom Günther.
Das bringt dir so also nichts.

Könntest du den lang offenen Request nicht in einen eigenen Prozess packen und den von deinen Hauptprogramm aus starten, steuern und ggf. killen?

Es gibt bestimmt noch eine elegantere Variante.

Christoph Schneider 27. Jun 2018 20:32

AW: Long running Rest API Call mit THTTPClient
 
Mit einem eigenen Prozess wäre zwar das Memory Leak entschärft, dafür müsste eine Interprozesskommunikation (bpsw. mit einer Pipe) alle eintreffenden Meldungen an den startenden Prozess übermitteln. Da erscheint mir der Aufwand zum Ertrag (keine aufsummierenden Memory Leaks mehr) gar etwas hoch. Beide Lösungen (Thread Kill vs. Prozess Kill) sind ein Murks.

Aus meiner Sicht müsste es wenigstens auf Api Level möglich sein, ein gestarter HTTP Request vom aufrufenden Thread in allen Fällen (also auch ohne Empfang von Daten) jederzeit wieder zu stoppen.
Ich glaube, ich schaue jetzt mal wie das unter Windows gemacht werden könnte.

Danke für die vielen wertvollen Ideen.

TiGü 28. Jun 2018 08:46

AW: Long running Rest API Call mit THTTPClient
 
Hast du ein Beispiel für eine öffentliche REST-Schnittstelle mit long running requests?
Meine bisherigen Erfahrungen mit REST habe ich nur mit Schnittstellen gemacht, die innerhalb von einer handvoll Sekunden geantwortet haben.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:35 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz