I have a cgi webapp running on Apache. The app has a webpage where an administrator can send one or more emails to club members. The mails all get sent perfectly, but the progress feedback shown to the administrator is unreliable. Testing locally by running the app from the IDE always works perfectly, but when the production cgi app is run on remote server, the administrator (who can be located anywhere in the world) sometimes sees “stuck” progessbars, and label-based status text which has not appeared at all, or has appeared, but not updated - but sometimes it all works perfectly!
First Code scenario:-
“send” button placed in WebContainer (itself placed on webpage), calls a “SendMyMailNow” method of the webcontainer. The method sets the ProgressBar parameters and Status Label text, then sets those objects to .visible = true, then the same method provides data to a SMTPSecureSocket object (which is placed as a Control of the WebPage in the IDE design). The method then calls the SendMail function of the socket. The socket’s “MessageSent” event is then used to update the ProgressBar and Status label text. The “MailSent” event is used to clear the status label text and to set ProgressBar.Visible to False.
Second Code scenario:-
Same as above, except that the “SendMyMailNow” method does not call the socket’s .SendMail function directly, but instead, calls a Thread.Run (where the Run event simply contains one statement: “MySMTP.SendMail”).
Both scenarios produce identical results.
Is there a better way to ensure reliable UI feedback, regardless of browser latency, etc??
All advice gratefully received!
Remember: when an event comes to the server (like a button push) all of the commands that are executed in direct response to that event happen before any response is sent to the browser. It’s also worth noting that you need to keep track of which session the request came from. If there is more than one active, you could be sending the events to the wrong Session.
With the Thread… Are you using a timer to send progress to the browser?
The only other thing I can think of off the top of my head would be to use a helper app… A separate console app which communicates with the main app via IPCSocket. The advantage is that this app could run on a separate core, and won’t bog down the main app while it does its work.
Thanks for the ideas, Greg. Am I right to locate the SMTPSecureSocket object in the WebPage, or should I place it as a Property of the Session object. Does it actually matter?
Why does it work sometimes?
Another possible strategy could be to have the push button start a timer (to periodically poll the Socket for progress events), and then call a thread to execute the mail sending code. That should leave the button thread idle, and hopefully the server will send updates to the browser at each timer cycle?? If so, where’s the best place to put the Thread object?
Do WebPage objects behave differently to objects stored in the Session object?
I do a lot of sending updates that come in from external sources at random times. I dont think it matters where you store the references to the various sockets or such. When the events fire they will be in the main thread, not the thread that is servicing your web app. What are you doing to restore the session when you want to do an async update?
The technique for that has changed several times since the WE started and Im not sure what the proper way is now, but Im doing this and it works. In this case the code is in a callback in a WebContainer that contains the UI that Im trying to display:
dim Context as new WebSessionContext(app.SessionForControl(self.Page))
and after doing that I can now send changes to the controls. Its interesting, controls that get their info from the regular WE pipe to the browser do not require this before changing them. Controls like images however that generate a link back to the server themselves to get their display do, otherwise no changes are displayed. So I dont know if this directly overlaps your problem or not.
Well, I have implemented a rather simple solution which appears to work very reliably. Same setup as per my original First Code scenario noted above, but with the following mods:-
The “Send” button code not only calls the “SendMyMailNow” method, but also turns on a WebTimer.
The SMTPSocket’s various events (Error / MailMessageSent / etc…) no longer interact in any way with the UI, but instead, these events simply update various text or integer variables (stored as properties of the Session object).
The WebTimer simply polls those variables every 1 second, and uses that data to update the WebPage ProgressBar and status labels.
When all mails in the queue have been sent (or an error is reported), the WebTimer is turned off.
Seems to provide a realistic UI feedback, with progressbar updating smoothly as mails are being sent. (Even with the cgi server located on another continent!).