Цитата:
Сообщение от
wojzeh
По
следам бременских музыкантов хотелось бы задать вопрос коллегам, имевшим опыт запуска сразу нескольких экземпляров класса в качестве batch задачи.
Какие-нибудь соображения?
соображения будут у меня же самого в виде отдельного постинга на блоге, а тут вкратце напишу по-русски.
налицо три бага, которые мешают адекватно отображать прогресс в случае нескольких прогресс-баров на стороне сервера.
во-первых, как было найдено коллегами ранее, параметр, регулирующий вообще запуск прогрессбар на стороне сервера, "заглушен" в вызове RunBase.
во-вторых, при создании прогрессбара также необходимо также передавать уникальный GUID, чтобы потом точно знать, какой именно бар "прогрессировать". иначе будет цепляться первый и процент исполнения "скакать" то туда, то сюда -- в зависимости от количества одновременно исполняемых задач.
ну, и в-третьих, несмотря на то, что метод kill помечен как "более не нужный", он всё-таки нужен, если по завершении всех задач мы действительно хотим удалить прогрессбар из таблицы SysProgress, иначе они будут там оставаться навсегда, так как преемник reset после удаления просто пересоздаст запись с теми же параметрами.
ниже пример вашего класса, который исполняется на сервере как batch, и необходимые коррективы в системных классах.
X++:
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
X++:
/*
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
X++:
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
X++:
// Begin: Alexey Voytsekhovskiy, reset bug fix
#obsolete void kill(boolean _toKill = false)
{
this.reset(_toKill);
}
// End: Alexey Voytsekhovskiy, reset bug fix
reset
/
X++:
/ 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
}
SysOperationProgressServer
reset
X++:
// 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<=numOfBars; i++)
{
// Begin: Alexey Voytsekhovskiy, reset bug fix
// if the task finished, we have to really kill the progress bar
if(!_toKill)
{
// End: Alexey Voytsekhovskiy, reset bug fix
select forupdate * from progress where progress.CallId == callId && progress.ProgressIndex == i;
progress.CallId = callId;
progress.SessionIdx = sessionIdx;
progress.SessionLoginDateTime = sessionLoginDateTime;
progress.ProgressIndex = i;
// any other default values?
progress.write();
}
// add the recid into the map
progressRecIds[i] = progress.RecId;
currentCount[i] = -1;
currentIncrement[i] = 0;
total[i] = 0;
text[i] = '';
}
caption = '';
animation = '';
ticksAtLastUpdate = 0;
conn.ttscommit();
}
catch
{
conn.ttsabort();
}
}