Триггер onEdit срабатывает на пользовательское редактирование ячейки, но не обязан запускаться, когда формула пересчитала результат. Поэтому автоматизация может видеть исходное изменение, но пропускать зависимые ячейки. Решение строится не на попытке заставить формулу вызвать edit-событие, а на явном обнаружении изменившегося результата.
Определите, какие формульные значения важны и с какой задержкой их допустимо обрабатывать. Для периодической проверки храните последнее обработанное значение или hash и запускайте функцию по time-driven trigger с блокировкой от параллельного выполнения.
Что проверить в первую очередь
Начните с воспроизводимого сценария: зафиксируйте время сбоя, идентификатор объекта, версию приложения или конфигурации и последнее известное рабочее состояние. Не меняйте несколько параметров одновременно. Один контролируемый шаг должен подтверждать или исключать одну гипотезу, иначе временное исчезновение симптома легко принять за исправление. Перед работой с данными и настройками подготовьте резервную копию и понятный способ отката.
- Уточните тип триггера: simple onEdit, installable edit, change или time-driven.
- Проверьте, меняется ли формула из-за ручного ввода, импорта, API или volatile-функции.
- Определите диапазон, который нужно отслеживать, и допустимую частоту проверки.
- Посмотрите Executions: функция могла не запускаться либо завершиться до нужной ветки.
Почему возникает проблема
Внешний симптом часто появляется не в том компоненте, где возникла первичная ошибка. Интерфейс может показывать неверное состояние из-за backend, очереди, кеша, прав доступа или внешнего API. Полезно проследить данные от источника до результата и найти первую точку расхождения. Это надежнее, чем исправлять последнее сообщение об ошибке или бесконечно перезапускать сервис.
- Пересчет формулы не является пользовательским edit-событием.
- Скрипт сам записывает значение и ожидает рекурсивного запуска onEdit.
- Формула импортирует данные асинхронно, и проверка выполняется раньше обновления.
- Триггер создан под другим аккаунтом и потерял разрешения.
- Сравнение строк не учитывает тип, локаль или формат даты.
Пошаговая диагностика
Диагностику проводите на тестовой записи или отдельном окружении. В журналах скрывайте токены, пароли, персональные данные и содержимое документов. Для каждого шага сохраняйте измеримый результат: код ответа, версию записи, идентификатор события, состояние процесса, контрольную сумму или время выполнения. Сравнение одной и той же операции до и после изменения помогает отделить причину от совпадения.
- Запишите в отдельный технический лист время запуска и считанное значение.
- Проверьте вручную функцию сравнения без event object.
- Сохраните hash нормализованного диапазона и сравните через минуту.
- Посмотрите quota, ошибки authorization и длительность выполнения.
- Добавьте LockService и проверьте, нет ли одновременных запусков.
Как выбрать механизм обнаружения изменений
Событийный onEdit подходит для прямого ввода, а вычисляемый результат требует polling, явного вызова из источника данных или собственного журнала версий.
- Time-driven trigger периодически сравнивает текущее и сохраненное состояние.
- Источник данных может вызывать webhook или Apps Script API после обновления.
- Контрольная ячейка или hash сокращает чтение большого диапазона.
- PropertiesService хранит небольшой cursor, но для большого состояния лучше отдельный лист или БД.
- LockService предотвращает двойную обработку при пересечении запусков.
Как исправить проблему
Разбейте исправление на небольшие обратимые изменения. Сначала устраните подтвержденную причину, затем повторите исходный сценарий и проверьте соседние функции. Массовое обновление данных запускайте на ограниченной выборке с отчетом и только после сверки расширяйте на весь объем. Не отключайте авторизацию, валидацию, шифрование или проверку сертификатов ради быстрого исчезновения ошибки.
- Вынесите обработку в функцию без зависимости от объекта onEdit.
- Создайте time-driven trigger и сохраняйте последнее успешно обработанное состояние.
- Нормализуйте даты, числа и пустые значения перед сравнением.
- Обрабатывайте только изменившиеся строки и записывайте idempotency key.
- После успешного внешнего действия атомарно обновляйте cursor, чтобы retry не создавал дубль.
Безопасный порядок внедрения
- Сохраните затрагиваемые данные, конфигурацию и текущие журналы, заранее проверив реальный способ восстановления.
- Повторите проблему на тестовом объекте без реальных списаний, рассылок и необратимых изменений клиентских данных.
- Зафиксируйте изменение в системе контроля версий или журнале работ вместе с причиной и планом отката.
- Проведите тест на нормальном сценарии, ошибочном вводе, повторном запросе, параллельной операции и временной недоступности зависимости.
- После выпуска наблюдайте логи, метрики и полный пользовательский путь, а не только один успешный запрос.
Как проверить результат
Разовый успешный тест недостаточен. Повторите операцию, проверьте крайние значения, одновременные действия и восстановление после перезапуска или временного сбоя. Для важного сценария сохраните автоматический тест либо короткий регрессионный чек-лист. Итог должен подтверждаться не только интерфейсом, но и состоянием базы, очереди, внешнего сервиса и журналом действий.
- Изменение исходной ячейки приводит к обработке нового результата формулы в допустимый срок.
- Повторный запуск без изменений не отправляет письмо и не создает запись.
- Ошибка внешнего API оставляет строку доступной для безопасного retry.
- Параллельные триггеры не обрабатывают одну версию дважды.
Типичные ошибки при исправлении
- Ожидать, что setValue автоматически вызовет onEdit.
- Сканировать весь лист каждую минуту без ограничения диапазона.
- Сохранять cursor до завершения внешнего действия.
- Использовать цвет или формат ячейки как единственный надежный статус.
Как предотвратить повторение
Профилактика строится вокруг явных контрактов, повторяемых релизов и наблюдаемости. Система должна не только работать сейчас, но и позволять быстро увидеть нарушение правила при следующем обновлении, росте нагрузки или сбое внешнего сервиса. Проверки полезно автоматизировать там, где ошибка уже привела к потерям времени, данных или заявок.
- Документируйте, какие изменения являются edit, а какие вычислением.
- Контролируйте ошибки Executions и срок последнего успешного запуска.
- Используйте batch-чтение и batch-запись вместо циклов по ячейкам.
- Храните явный статус обработки и идентификатор результата.
Что подготовить для технического разбора
- Описание ожидаемого и фактического поведения с точной последовательностью действий.
- Время проблемы, идентификатор тестового объекта и версии затронутых компонентов.
- Фрагменты журналов до и после ошибки без секретов и персональных данных.
- Перечень последних изменений и уже выполненных проверок.
- Безопасный доступ к тестовой среде либо способ воспроизвести сбой без влияния на клиентов.
Частые вопросы
Поможет ли installable onChange?
Он реагирует на структурные изменения таблицы, но не превращает обычный пересчет формулы в надежное событие значения.
Как часто можно проверять лист?
Частота зависит от тарифа и quota. Выбирайте минимально необходимую, сокращайте диапазон и обрабатывайте данные пакетно.
Когда нужна помощь специалиста
Если Apps Script пропускает изменения формул, я могу перестроить обработку на контроль состояния, расписание или webhook, убрать дубли и настроить журнал ошибок и повторов.