Источник:
http://alexvoy.blogspot.com/2013/12/...-progress.html
==============
<div dir="ltr" style="text-align: left;" trbidi="on">In AX 2012 we deal with three types of progress bars:
- SysOperationProgress
- SysOperationProgressEmbedded
- SysOperationProgressServer
that initialized in
RunBase.
progressInit method.
What concerns the latter that runs on the server side for batch jobs and tasks, I have never seen before that the Progress field changed during batch tasks execution.
This is because
RunbaseProgress Construct method is called without
_disableProgressWithoutGUI parameter; nevertheless, it exists in its own
New method. This parameter is always TRUE.
I do not know if this option is disabled by purpose having some other developing perspectives in mind, or simply by mistake.
In fact, it is not enough just to extend constructors accordingly to pass this parameter from your own processing class down to
SysOperationProgressServer methods. There is another bug in
Construct.
This bug does not take into account the caller class that creates its progress bars passing an empty GUID, so that
Update method always refreshes the first progress bar found in
SysProgress table. In other words, if you started a few batch tasks simultaneously, you will see an interesting progressing: after 100% it starts from zero and so on until the last task finishes. No progressing for the rest of the tasks.
The third bug is in
Reset method, which actually run in turn by
progress.Kill method (now marked as obsolete). Unfortunately, I do not inderstand the logic of this approach to reset the progress bar when my tasks is finished. From my point of view, it must be really 'killed' it in the end.
All in all, the following changes in forementioned objects fix the problem.
Your class example
// Sample of your class supposed to be processed as a batch
void processSomething()
{
// maximum number of lines to be processed
totalLines = ...;
// to enjoy our boring user during a few next hours...
this.progressInit("@SYS59011", totalLines, #AviUpdate, 1, null, false, newGuid());
// create the progressbar on the server side if it is not a client session with a new unique GUID
while (...)
{
...
}
progress.kill(true);
}
RunBase
progressInit
/*
This method is called to initialize the Progress object in runbase.
*/
public void progressInit(
str caption,
int64 total,
Filename animation,
int numOfBars = 1,
FormBuildControl embedded = null,
// Begin: Alexey Voytsekhovskiy, bug fix
boolean _ifOnSrvBypass = true,
guid _callerId = str2guid('')
// End: Alexey Voytsekhovskiy, bug fix
)
{
if (! progress)
progress = RunbaseProgress::construct(numOfBars,embedded
// Begin: Alexey Voytsekhovskiy, bug fix
// to set progressbar on the server side
,_ifOnSrvBypass, _callerId);
// End: Alexey Voytsekhovskiy, bug fix
progress.setCaption(caption);
progress.setTotal(total);
progress.setAnimation(animation);
}
RunbaseProgress
construct
public static RunbaseProgress construct(
int _numOfBars = 1,
FormBuildControl _embedded = null,
boolean _ifOnSrvBypass = true,
// Begin: Alexey Voytsekhovskiy, bug fix
guid _callerId = str2guid('')
// End: Alexey Voytsekhovskiy, bug fix
)
{
return new RunbaseProgress(_numOfBars,_embedded, _callerId, -1, DateTimeUtil::minValue(), _ifOnSrvBypass);
}
kill
// Begin: Alexey Voytsekhovskiy, reset bug fix
#obsolete void kill(boolean _toKill = false)
{
this.reset(_toKill);
}
// End: Alexey Voytsekhovskiy, reset bug fix
reset
// Begin: Alexey Voytsekhovskiy, reset bug fix
void reset(boolean _toKill = false)
// End: Alexey Voytsekhovskiy, reset bug fix
{
if (oprProgress)
oprProgress.reset();
else if (oprProgressServer )
// Begin: Alexey Voytsekhovskiy, reset bug fix
oprProgressServer.reset(_toKill);
// End: Alexey Voytsekhovskiy, reset bug fix
}
<div>
SysOperationProgressServer
reset
// Begin: Alexey Voytsekhovskiy, reset bug fix
public void reset(boolean _toKill = false)
// End: Alexey Voytsekhovskiy, reset bug fix
{
UserConnection conn;
SysProgress progress;
int i;
if ( bypass )
return;
conn = new UserConnection();
progress.setConnection(conn);
conn.ttsbegin();
try
{
// delete existing recoreds for this session.
delete_from progress
where progress.SessionIdx == sessionIdx &&
progress.SessionLoginDateTime == sessionLoginDateTime;
// create records for this session based on number of bars
for (i=1; i