RTC Forums
November 25, 2024, 04:40:09 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: Calling ReportStatus in a service with a TRtcHttpClient  (Read 7126 times)
barbarland
RTC Expired
*
Posts: 7


« on: February 18, 2010, 04:52:42 PM »

Hello Danijel,

I use RTC in a Service (with SvCom library).
I use a TRtcHttpClient and TRtcDataRequest to send a stream to a server (HTTP post).
Everything works well.

But sometimes the request is time consuming (server slow, stream is large in size...).
My service should call ReportStatus to report that it is alive.

I also use WaitForCompletionEx to catch exception like this:
Code:
    try
      SendRequest.WaitForCompletionEx;
    except
      on E:Exception do
        LogToEventViewer(E.Message);
    end;
This is very easy to use.

How can I use a Timeout with WaitForCompletionEx (WaitForCompletion or DoWaitForCompletion) to call ReportStatus from time to time.
For example every 5000 ms ?

I know I can use SendRequestDataSent to call ReportStatus periodically.
But maybe there is a better place to do the job...

Regards,
Barbaland

Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #1 on: February 18, 2010, 09:42:11 PM »

You should NOT use Timeouts with WaitForCompletionEx if you want the request to finish, because WaitForCompletionEx will cancel the request after the Timeout and you will NEVER get a result for that request if it times out. Timeouts are used ONLY if you want to limit the time you want to wait for a result and do NOT care what happens to the data after your timeout has expired.

Please skip the rest of the text in this reply and go to the next reply (below) for the answer to your question. The text below is for developers who want to DOWNLOAD reports FROM the Server and not UPLOAD reports TO the Server (which is what you seem to be doing - but I misread your post the 1st time).

For anyone who wants to have reports generated by the Server and have the Client informed of the generation progress, read along ...

If you want to poll the Server while waiting for your report, I can think of three options (other developers might have more or other ideas):

Option 1:

When the Client requests a report to be generated by the Server, you will need to create a Thread on the Server insidewhich your report generation will be running, while you return a result to the Client immediately, with basic information like "report XYZ running" (or what ever you might know before you even start report generation). The Client should then poll the Server periodically to check how far the report is generated and maybe just return the information about where the report can be downloaded (URL?) when it is finished. You can always write the report to a local temporary file on the Server and leave it there until the Client comes to get it.

Option 2:

You will need to use 2 physical connections from the Client to the Server. One will be used to start report generation and should be event-driven and NOT blocking (NO WaitForCompletion!), while the other connection (a separate TRtcHttpClient and TRtcDataRequest components) is used to periodically check the status on the Server and show a progress bar (or what ever you want). When data arrives, you will get it in the OnDataRceived event of the first connection component, just like now. So, the only difference here is that you will NOT use WaitForCompletionEx at all, but will instead use a TTimer with a separate connection to check the status of your report.

Option 3:

The Server will break its report generation into several finite and up-front defined number of smaller steps, prepare the response header from its OnDataReceived event, but Write only the header and 1 byte of data (or a fixed-length string, if you prefer to send more info on start) to the Client from the OnDataReceived event, BEFORE you start generating the report. Then, the Server will use the OnDataSent event to generate the report in your previously defined finite number of steps and send only 1 byte of data (or a fixed-length string) from each OnDataSent event.

Data sent from the Server before it starts generating the report and data sent from the Server after each step was processed needs to be fixed-length, because you will need to calculate the complete Response.ContentLength BEFORE you start sending out ANY data. But, by using "Response.ContentLength" and "WriteHeader" from the OnDataReceived event (provided you have calculated your expected ContentLength correctly), the Server will be able to start sending data to the Client immediately and send more data to the Client as it continues processing the request (generating the report), because it will know how long the expected response will be and the RTC SDK will be able to send bits and pieces to the Client as they are ready.

As a result, the Client will start receiving a response from the Server piece-by-piece and be able to use it to display a progress bar or log the progress (or whatever) at the exact same speed the Server is generating the report. And after the last piece of the report was generated by the Server and the Server sends the last piece of response to the Client, the Server should store the report locally (hard drive), where it should wait for the Client. Once the Client receives the last piece of data from the Server, provided you have put enough information into your response, the Client will know the Server has completed the report and will be able to use this info to send a new request to the Server and get the report, which is now completed and stored locally on the Server.

Both requests can be done by using WaitForCompletionEx. To notify the user about the report generation status, the 1st request (which requests a report to be generated) can access the GUI and show a progress bar or what ever you want.

In rough lines, that would be the options I can recommend. I would personally recommend you to go with option 3, for several reasons. First, it only requires using a single connection and does NOT require creating separate threads on the Server to check the report generations status. In addition, your report generation can be cancelled by the Client between each step simply by closing the connection to the Server, in which case the Server will get the OnConnectLost event, can clean up its memory (you will probably be using database objects or something like that to get the data for the report) and will NOT just continue blindly (which would mean consuming server resources for nothing).

But, the 3rd option might also need some "aroud-the-corner" thinking and might not be doable at all if you are generating your reports by using some report generation tools which can only generate the report in a single run. In that case (if you cant go with option 3), you can pick between Option 1 and 2. In both cases, you will need to write thread-safe code on the Server and implement some kind of notification between your 2 threads running on the Server.

I hope that is what you've had in mind. If you were looking for something "simple", I am afraid there is no "simple" solution when you are using HTTP and want status reports for a running request.

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #2 on: February 18, 2010, 10:14:52 PM »

I've just re-read your question and now I see that you are sending data TO THE SERVER and not downloading it FROM THE SERVER. If you have already read my reply, you will probably have noticed that I am talking about RECEIVING data FROM THE SERVER. If anyone needs to do that, above is the explanation.

For what you want to do, if you are generating the report on the Client, the only thing you need to keep in mind is that you should send your data to the Server in smaller chunks and use the OnDataSent event on the RtcDataRequest component to send more. I am not sure what you mean by "report status", but as long as you are sending data to the Server, the Server will know you are alive and you do not need to do anything extra-ordinary. If you mean that you want to report your sending status to the user sitting in front of the Client PC, you are correct that OnDataSent is the best place to do it.

Best Regards,
Danijel Tkalcec
Logged
barbarland
RTC Expired
*
Posts: 7


« Reply #3 on: February 19, 2010, 10:31:34 AM »

Thank you Danijel for the detailed post.

But my own post was too much concise.
And the function  ReportStatus is the source of confusion.
I would say TService.ReportStatus to be more accurate.
Sorry.

But let me explain my problem.
I wrote a Windows Service (services.msc).
I use SvCom from Aldynsoftware but the situation is the same with the standard Delphi TService VCL (unit SvcMgr.pas).
(your useful RTCWebServer project also use a TService)

Sometimes my Windows Service needs to upload a file to a server.
To upload the file I use a TRtcDataRequest and I call WaitForCompletionEx.

If uploading file takes more than TService.WaitTime I need to call TService.ReportStatus.
Otherwise the operating system thinks and reports that the service is down (I see a service failure in services.msc).
I also got unpredictable results when Windows Shutdown (for example).

Readers who want more information about ReportStatus can read Delphi helpfile or
http://www.aldyn.ru/demos/0002/3.html

So finally I just want to know the better strategy to call TService.ReportStatus during upload.

Hope I am more clear.
Please be indulgent with my English or clumsiness.

Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #4 on: February 19, 2010, 10:46:08 AM »

If you break the data you are sending into small enough chunks and call "TService.ReportStatus" from the OnDataSent or OnDataOut event, your problem should be solved. The important thing to note here is that you need to break your data into small packages and not try to send a lot of data with a single Write() call from OnDataSent. The smaller your chunks, the more often OnDataSent and OnDataOut events will be callled.

As an alternative, since the RTC SDK can be used in non-blocking and multi-threaded way, you could have the RTC SDK do the sending in background threads and/or in a non-blocking way, in which case the main thread of your Service will be idle. But then you should avoid using WaitForCompletion or WaitForCompletionEx, because that would negate the whole point of using a background thread ;-)

Or ... if TService.ReportStatus can also be called from background threads and have the same effect, you could create a background thread just for calling TService.ReportStatus, independently of any other things you are doing.

Best Regards,
Danijel Tkalcec
Logged
SteveM
RTC License++
*****
Posts: 16


« Reply #5 on: February 19, 2010, 11:26:44 AM »

Hi Barbaland,

I second the thread option, I do similar in several of my apps, and doing transfers in a separate thread(s) makes it a lot simpler to keep SCM happy...

Steve..
Logged

Stephen Mott - Lanboss Software
barbarland
RTC Expired
*
Posts: 7


« Reply #6 on: February 19, 2010, 11:35:05 AM »

I will probably use your first suggestion (small chunk + OnDatasent).

Maybe I'm wrong but I'm not foolhardy enough to implement/debug multi-thread application in a Windows Service Sad

Thank you for your fast reply.

Kind Regards
Barbaland
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.028 seconds with 17 queries.