Asynchronous AppServer Call

Dawn M

Member
Progress 9.1C
Windows XP
HP-UX running Unix

I am attempting to run a program using AppServer, asynchronously. Here's what my code looks like...

* On a window, I have an "OK" button with the following code:

/*** Run Report Program ***/

run clientProgram.p persistent (input value-1, input value-2).

message "..." view-as alert-box.

apply 'close' to this-procedure.

* In the clientProgram.p procedure, the main block contains:

/*** Connect To AppServer ***/

{appserver.i}

/*** Run Report Program ***/

run report.p on hAppSrv asynchronous set hASynch
event-procedure "report-done" in this-procedure
(input value-1, input value-2, output rptDone) no-error.

And the report-done procedure contains:

define input parameter xdone as logical no-undo.

if hSynch:error or
hSynch:stop then
message "ERROR" view-as alert-box error.

else
message "Success" view-as alert-box.

hAppSrv:disconnect().

delete object hAppSrv.

delete object this-procedure.

The problem I'm getting is that once the window procedure with the "OK" button is closed and the user goes to do something else, when the report.p program on the server finishes, I get the error message "Procedure [whatever program the user is in] has no entry point for report-done".

This is my first attempt at an asynchronously called program. What am I missing or doing wrong?

Any answers welcome.
 

GregTomkins

Active Member
When you said "And the report-done procedure contains", does that imply that the same procedure file that contains "run report.p on hAppSrv asynchronous set hASynch event-procedure "report-done" in this-procedure" also contains the line "PROCEDURE report-done:"? Because if not, it needs to (assuming I am reading all of this correctly).
 

Dawn M

Member
Yes, both the run of report.p and the report-done internal procedure are in the same program (w-window.w).
 

GregTomkins

Active Member
Oh, I think I see now; they are starting the report, then closing the .W that contains the callback procedure. If you leave the window open, everything works correctly - correct?

If so, you need to restructure this so that the procedure containing the callback is still active at the time when the AppServer call finishes. You could have a generic "handle AppServer completion" procedure in whatever program is upstream of the window procedure. Or something like that.

Or, maybe you don't actually care about when it finishes ... maybe you actually want "fire and forget" ... I think you can achieve this by omitting the EVENT-PROCEDURE clause.
 

Dawn M

Member
Oh, I think I see now; they are starting the report, then closing the .W that contains the callback procedure. If you leave the window open, everything works correctly - correct?

If so, you need to restructure this so that the procedure containing the callback is still active at the time when the AppServer call finishes. You could have a generic "handle AppServer completion" procedure in whatever program is upstream of the window procedure. Or something like that.

Or, maybe you don't actually care about when it finishes ... maybe you actually want "fire and forget" ... I think you can achieve this by omitting the EVENT-PROCEDURE clause.

I'd like the "fire and forget it" option. The only thing I need to do (which is what I'm trying to do in the report-done internal procedure) is disconnect the AppServer process and delete the handles that are used to connect to it.
 

GregTomkins

Active Member
Right. Then you need the callback to be in some procedure that will still be active when the AppServer call finishes. Eg., instead of 'IN THIS-PROCEDURE', it should be 'IN x', where 'x' is a handle to, perhaps, the program that stays alive the whole time the P4GL client is active.

In our system, we have zillions of reports, some of which run for a long time. When we wrote it, async AppServers were a gleam in someone's eye so we wrote an entire subsystem to execute jobs completely ouside of the AppServer infrastructure (basically using Unix daemons).

When async AS's came out, we thought hard and decided our home-grown solution was better, because it has the major advantage of not tying up any of our AppServer agents. Plus, we can do things like make sure only a fixed number of reports run at once. For us, I think this was a good decision, though it would be overkill for many apps.
 

Dawn M

Member
Right. Then you need the callback to be in some procedure that will still be active when the AppServer call finishes. Eg., instead of 'IN THIS-PROCEDURE', it should be 'IN x', where 'x' is a handle to, perhaps, the program that stays alive the whole time the P4GL client is active.

In our system, we have zillions of reports, some of which run for a long time. When we wrote it, async AppServers were a gleam in someone's eye so we wrote an entire subsystem to execute jobs completely ouside of the AppServer infrastructure (basically using Unix daemons).

When async AS's came out, we thought hard and decided our home-grown solution was better, because it has the major advantage of not tying up any of our AppServer agents. Plus, we can do things like make sure only a fixed number of reports run at once. For us, I think this was a good decision, though it would be overkill for many apps.

Thanks for your response, Greg.

Unfortunately, there are hundreds of procedures that the user could be in, so it would be completely unpractical to put the "report-done" IP in all those programs.

And, I was under the impression that the event-procedure could not be an external procedure, but needed to be an internal procedure of the calling procedure.

In another attempt to get this working, the OK button of w-window.w ran a persistent procedure (run rpt.p), which in turn, connected to the AppServer, ran the report procedure (report.p) and contained the "report-done" internal procedure. I still received the (8982) error message.

My company also has a "demon" type of set-up we use for most of our reports. Unfortunately, this report takes so long to run (1+ hours), that we don't want to tie up these processes on such a lengthy report.

Any more ideas/suggestions?
 

GregTomkins

Active Member
You don't want to tie up a daemon, but you are willing to tie up an AppServer agent? For us, that would be a major WTF. We go to great lengths to try to keep all our AppServer calls sub-second.

So, in our app, we have a program that the user comes into called 'desktop.w'. From there, the user can run hundreds of procedures, some of which might remain persistent indefinitely, some of which come and go. So we would put the 'report-done' procedure in 'desktop.w' because we know it will always be active. Then we would say RUN... ASYNC.. IN h_handle_to_desktop_w. (There are many ways you could keep track of this handle, such as an input parameter, super procedure, global variable, IP in the calling procedure, via SOURCE-PROCEDURE, etc.)

You could also run the cleanup as a session super, which is another procedure which you can generally count on being active for the duration of the P4GL session. We generally avoid session supers, but we do use them for two specific purposes and quite possibly would use one in a case like this.
 

Dawn M

Member
You don't want to tie up a daemon, but you are willing to tie up an AppServer agent? For us, that would be a major WTF. We go to great lengths to try to keep all our AppServer calls sub-second.

So, in our app, we have a program that the user comes into called 'desktop.w'. From there, the user can run hundreds of procedures, some of which might remain persistent indefinitely, some of which come and go. So we would put the 'report-done' procedure in 'desktop.w' because we know it will always be active. Then we would say RUN... ASYNC.. IN h_handle_to_desktop_w. (There are many ways you could keep track of this handle, such as an input parameter, super procedure, global variable, IP in the calling procedure, via SOURCE-PROCEDURE, etc.)

You could also run the cleanup as a session super, which is another procedure which you can generally count on being active for the duration of the P4GL session. We generally avoid session supers, but we do use them for two specific purposes and quite possibly would use one in a case like this.

Hey, I'm just the programmer, so I just try to code it how they want it. :confused:

Another problem is that we don't have the code to our menuing system or the initial start-up procedure. So, I really can't put any code in there. (Nothing like coding with one hand tied behind your back.)

I think I will have to create a super procedure containing "report-done" and run it when the user enters the appropriate "module".

Thanks so much, Greg. You have be very helpful!
 
Top