Что происходит, когда я "сплю" в ГАЗЕ? (временное ограничение по времени выполнения)

За этим (не так много, я признаю...) забавным вопросом является реальный вопрос об обходном пути, который я использую, не понимая, как он работает.

Сначала краткое описание моего варианта использования, все это происходит в UiApp с привязкой к документу, отображаемом на боковой панели:

Я должен создать и отправить по электронной почте пару сотен документов в приложении для слияния, написанном на GAS. Конечно, это занимает слишком много времени, чтобы обрабатываться в одном пакете, не превышая 5-минутного лимита времени выполнения, поэтому я попробовал несколько различных обходных путей, чтобы выполнить задачу:

  1. использовать метку времени (сохраненную в ScriptProperties), когда я запускаю процесс, и когда я достигаю предопределенного значения вблизи предела, я сохраняю текущие значения (указатели, полезные переменные...) и возвращаюсь к пользовательскому интерфейсу, прося пользователя продолжить (или нет). Это работает довольно хорошо, но для выполнения всей задачи нужны действия человека.
  2. Поэтому я настраиваю решение, используя триггер таймера, который я создаю при первом вызове обработчика, и этот триггер вызывает функцию создания / отправки документа. Это также хорошо работает, но триггер, вызываемый функцией, не может взаимодействовать с пользовательским интерфейсом, так как кажется, что только функции-обработчики могут обновлять пользовательский интерфейс. Проблема в том, что я не могу ни показать прогресс, ни легко показать, когда процесс закончится.
  3. Затем я вспомнил небольшое приложение, которое некоторое время назад написал просто для забавы: это был таймер, который использовал checkBox в качестве триггера для обработки сервера (из идеи, давно предложенной Romain Vialard на старом форуме Google), и решил попробовать это хитрость в моем процессе отправки почты.

Он работает отлично, я обрабатываю 40 пакетов документов каждый вызов (в течение примерно 3 минут), затем делаю паузу на некоторое время и начинаю снова, пока не закончится. Каждый вызов инициируется обработчиком связанного сервера checkBox, сам флажок изменяется в функции обработчика, создавая таким образом свой собственный триггер.

Мой вопрос (наконец-то;-): зная, что весь процесс может занять от 30 до 60 минут, насколько точно это возможно?Как / почему эти функции-обработчики сервера рассматриваются как множественные процессы, поскольку они создаются внутри самой функции?

Я надеюсь, что я достаточно ясен, (в чем я сомневаюсь, так как это немного запутано в моей голове:-)

Ниже я приведу код приложения для тестирования часов, которое дало мне идею: оно, вероятно, облегчит понимание.

function doGet() {
  var app = UiApp.createApplication().setTitle('Counter/Timer');
  var Panel = app.createAbsolutePanel().setStyleAttribute('padding','35');
  var counter = app.createHTML().setId('counter').setHTML('<B>Timer = wait</B>').setStyleAttribute('fontSize','40px');// set start display
  var clo = app.createTextBox().setName('clo').setId('clo').setValue('0').setVisible(false);//set start value in seconds
  var handler1 = app.createServerHandler('doSomething').addCallbackElement(Panel);
  var chk1 = app.createCheckBox('test1').addValueChangeHandler(handler1).setVisible(true).setId('chk1').setVisible(false);
  app.add(Panel.add(chk1).add(counter).add(clo));
  chk1.setValue(true,true);// start the process
  return app}

function doSomething(e) {
  var app = UiApp.getActiveApplication();
  var xx = Number(e.parameter.clo);
  var disp = app.getElementById('counter')
  xx++ ;// replace by xx-- to count downwards
  if(xx>600){ // 10 minutes timeout for example
  disp.setHTML('<B> GAME OVER ;-)</B>').setStyleAttribute('fontSize','80px').setStyleAttribute('color','RED')
  return app
  }
  var cnt = app.getElementById('clo').setValue(xx)
  disp.setHTML('<B>'+T(xx)+'</B>')
  Utilities.sleep(1000); // instead of sleeping do something !
// below comes the "active" part
  var chk1 = app.getElementById('chk1').setValue(false,false)
  var chk1 = app.getElementById('chk1').setValue(true,true)
  return app;
}

function T(val){
  var min = parseInt(val/60);
  var sec = val-(60*min);
  if(sec<10){sec='0'+sec}
  if(min<10){min='0'+min}
  var st = '>  '+min+':'+sec
  return st
}

введите описание изображения здесь

1 ответ

Решение

Утверждение, что вызовы функций-обработчиков сервера не являются независимыми процессами, поскольку они "создаются внутри самой функции", не совсем верно.

Вы установили элемент checkBox chk1 с обработчиком сервера doSomething, Каждый раз, когда проверяется checkBox, событие отправляется на сервер. (... и ваш сценарий вызывает эти события с каждым chk1.setValue() вызов) checkBox и окружающий код пользовательского интерфейса работает в вашем браузере - нажмите "показать источник" или используйте проводник, чтобы увидеть, что было передано вашему браузеру серверами Google. (Предупреждение - это запутано. Но вы можете узнать некоторые из ваших строк, и из этого ваш код на стороне клиента.)

Вот что мы рассказали в документации для Class ServerHandler:

Когда ServerHandler вызывается, функция, на которую он ссылается, вызывается на сервере скриптов приложений в "новом" скрипте.

Это ключ к увеличению вашего рабочего времени: каждое отправленное событие приводит к вызову doSomething() в совершенно новом рабочем контексте - вы как будто открыли редактор скриптов в другом браузере и нажали "запустить" на вашем скрипте. "Свежий" скрипт не имеет доступа к значениям var предыдущего запуска... но он также имеет свой собственный набор операционных ограничений, включая таймеры.

PS: Вы должны убедиться, что обработчик на стороне сервера является "потокобезопасным", используя Lock, поскольку вы получаете доступ к общим ресурсам, к которым могут обращаться несколько экземпляров doSomething() Перезвоните. В связи с этим, можно достичь другого предела с помощью этого сценария:

Снимок экрана - ошибка

Просто для удовольствия, я прокомментировал .setVisible(false) на chk1, так что флажок будет виден. Затем я быстро нажал несколько десятков раз. Отображение времени вышло из строя, и в итоге выскочила указанная выше ошибка. (несколько минут спустя) Конечно, это искусственная ситуация, но все же это состояние ошибки, которого легко избежать.

PPS: Интересно, можно ли использовать один и тот же метод для отправки нескольких параллельных обработчиков на стороне сервера и, таким образом, сократить затраченное время на выполнение всей работы?

Другие вопросы по тегам