Managing asynchronous operations
Definition
Because an operation is stateless and handles a list of parameters, it is possible to launch it asynchronously. When this happens:
- A temporary process executes the operation and receives the parameters.
- The user who launches the operation can take control and continue to work in his/her session while monitoring the execution progress.
- The temporary process ends automatically when the operation ends or if the server stops.
To allow the user to control the asynchronous running task, a set of APIs is available and described below.
The Context of execution
An operation is stateless. The code that is executed during the operation run has access to this
, but the instance is empty. However, it can be filled using the AREAD or AINIT method. The parameters sent when calling the method are available as local variables.
Because this execution is asynchronous, the results need to be stored in the database, possibly in log files. When the execution ends, the instance is destroyed.
An asynchronous operation can run silently in the background, but it might be useful for a user to monitor the execution of this task. The user can view details in a dialog box that displays at the top of the page:
This dialog box opens automatically if the operation uses the appropriate API. Information messages can show the progress of the operation. The user can hide and reopen the dialog box by clicking the small icon highlighted in the red square.
An Abort link is also present, and an API allows the developer to check periodically if the execution has stopped.
When the operation is finished, the Abort
link is replaced with a Download
link. The user can download a file published by an API that could include a log file or any other results.
APIs available to control the execution
The following APIs, which are available to control the execution of asynchronous tasks, are all subprograms located in the same library.
Library ASYRASYNC
Call ASYNCTRACK
This call creates the dialog box if it doesn't already exist, and displays a message with the phase name and phase detail. A completion percentage can also be shown.
The parameters are the following:
Code | Type and dimension | Contents |
---|---|---|
CONTEXT | ACTX instance | Current context. |
PAHASE_NAME | Char | Current phase to be dispayed. |
PHASE_DETAIL | Char | Current detail to be displayed. |
PERCENT | Integer | Progression percentage in the range 0-100. |
Func ABORTREQUEST
This function checks if the user requests the task to be aborted. It returns '0' if no abort request was sent, and '1' otherwise.
The parameters are the following:
Code | Type and dimension | Contents |
---|---|---|
CONTEXT | ACTX instance | Current context. |
Call ADDDIAGNOSE
This call adds a line in the text displayed in the bottom of the panel, in the diagnostics list.
The parameters are the following:
Code | Type and dimension | Contents |
---|---|---|
CONTEXT | ACTX instance | Current context. |
DIAGNOSE_TEXT | Char | Diagnose text. |
DIAGNOSE_STATUS | Integer | Status value as operation return them (can be CST_ASUCCESS, CST_AINFO or CST_AERROR). |
Call LINKDOWNLOAD
This call adds a download link to a file that has been placed in a standard volume.
The parameters are the following:
Code | Type and dimension | Contents |
---|---|---|
CONTEXT | ACTX instance | Current context. |
DATA_TYPE | Char | content type that describes the format of the downloadable file. |
PATH | Char | The fila path on a standard volume (for instance, "[MYVOL]/myfile.tra", whre [MYVOL] has been defined in the "a href="../administration-reference/supervisor-administration-volumes.md">volume table. |
Example
# This example is not based on the standard tables described in Sage X3.
# Let's imagine a link on the COUNTRY representation (class COUNTRY), that allows you
# to trigger a method that posts all the invoices in an accounting system not yet accounted for
# and addressed to customers who are located in the corresponding country.
# The current currency instance is CURRENCY.
# The parameter sent is the current country (called COUNTRY).
# The invoice (main table INVOICE) has a CUSTOMER reference column, a POSTED column (0 if not posted).
# The INVOICE class has a POST_IT method.
# Extract from script associated to the COUNTRY class:
$METHODS
Case AMETHOD
When "POST" : Gosub POST_COUNTRY
...
Endcase
Return
...
$POST_COUNTRY
# Miscellaneous declarations
Local File CUSTOMER [CUST]
Local File INVOICES [INV]
Local Instance CUR_INV using INVOICE
Local Instance MYLOG Using C_ALOG
Local Integer OK
Local Char LOGFILE_NAME(100)
# Let's generate the country class
OK=Fmet this.AREAD([L]COUNTRY)
If OK <> [V]CST_AOK : End : Endif
# Let's generate a class to generate the log
MYLOG=NewInstance C_ALOG AllocGroup Null
# Open the log file
OK=fmet MYLOG.ABEGINLOG("Invoice posting")
LOGFILE_NAME=fmet MYLOG.AGETNAME
# How many invoices ?
Local Integer INV_COUNT, CUST_COUNT, INV_NUMBER
Link [INV] with [CUST]CUSTKEY=[INV]CUSTOMER As [JOIN] Where [CUST]COUNTRY=this.COUNTRY and [INV]POSTED=0
& Order By Key CUSTDATE=[CUST]CUSTKEY;[INV]INVDATE
INV_NUMBER=rowcount([JOIN])
# Let's perform a double loop on invoices
For [JOIN]CUSTDATE(1)
CUST_COUNT+=1
For [JOIN]CUSTDATE
# Let's update the asynchronous box for every invoice
Call ASYNCTRACK(this.ACTX,
& "Managing customer"-[CUST]NAME,
& "Invoice"-[INV]INVNUM,
& int(100*(INV_COUNT/INV_TOTAL))) From ASYRASYNC
# Let's call the invoices method to generate and post it
CURINVOICE = NewInstance INVOICE AllocGroup null
OK=fmet CURINVOICE.AREAD([INV]INVNUM)
If OK<>[V]CST_AOK
Call ADDDIAGNOSE(this.ACTX,"Error on invoice"-[INV]INVNUM-"reading",OK) From ASYRASYNC
Else
OK=Fmet CURINVOICE.POST_IT
If OK=[V]CST_AOK
OK=fmet MYLOG.APUTLINE("Invoice"-[INV]INVNUM-"successfully posted",OK)
Endif
Endif
INV_COUNT+=1
FreeInstance CURINVOICE
Next
# Check if the user wants to stop only when a complete customer has finished
If func ASYRASYNC.ABORTREQUESTED(this.ACTX)
Call ADDDIAGNOSE(this.ACTX,"Interruption. "-num$(INV_COUNT)-"invoices posted",[V]CST_AWARN) From ASYRASYNC
Break
Endif
Next
# Now the generation is complete
OK=fmet MYLOG.APUTLINE(num$(INV_COUNT)-"invoices(s) successfully posted for"-num$(CUST_COUNT)-"customers",[V]CST_AOK)
OK=fmet MYLOG.AENDLOG
# Let's allow the log file (in [TRA] volume) to be downloaded
Call ADDLINKDOWNLOAD(this.ACTX,"ATYPE7","[TRA]/"+LOGFILE_NAME) From ASYRASYNC
FreeGroup MYLOG
End
Note
Using these API is of course important if the operation is defined as Asynchronous in the link definition of the representation. But if the operation is described as synchronous, the previous calls will not cause an error: they will simply do nothing. This means that the design of the script associated with a task that might be called in asynchronous mode does not need to be tested if it is the case or not.