Простым смертным иногда кажется, что компании вроде Google, Apple и Amazon — бесконечно сильные исполины. Они ежедневно таскают на своих плечах все свои сервисы, доступные практически каждому человеку на планете, а каждый пользователь, в свою очередь, имеет безграничный доступ к вычислительным ресурсам этих компаний.
Отчасти это так. Тот же Google в секунду обрабатывает количество запросов, которое, кажется, у нормального человека в голове уложиться не может. И такой сервис у него (и не только у него) — не один.
При повседневном использовании мы редко приближаемся к ограничениям, установленным то здесь, то там, чтоб наплыв пользователей в одну точку случайно не положил весь сервис в целой стране или даже регионе. Или не случайно, но об этом лучше расскажут безопасники.
Мы в «Собаке Павловой» начали строить дизайн-задачник на базе Google Spreadsheet. Мы смогли реализовать на них все, что хотели, оставаясь в парадигме No-code. Если не слышали — это когда продукт строится без кода и толп программистов, на специальных сервисах. Небольшие скрипты, написанные кодом, не в счет.
Всеядность и стабильность работы Таблиц нас настолько впечатлили, что особых проблем с масштабируемостью мы не ожидали. Но уже при первом массовом запуске студентов на обучение поняли, что зря. У всех иногда лапки, и у таблиц Google тоже.
Часть конструкций в нашем задачнике живет благодаря возможности передавать данные из определенных ячеек и диапазонов из одной таблицы в другую — с помощью формулы IMPORTRANGE. Так мы раздаем контент в таблицы студентов, немного усложняем жизнь современным Робин Гудам и собираем данные для статистики.
Когда нагрузка небольшая, задачники работают отлично: данные подтягиваются достаточно быстро, ничего не сбоит и вообще все максимально красиво.
Но как только нагрузка увеличивается — начинается ой.
Пока не будем вдаваться в подкапотные тонкости ошибки, расскажем о них позже. Но результат у нее очень интересный — если IMPORTRANGE не смог получить содержимое ячеек, на которые ссылается, то он ничего не вернет. Вообще. И руками повторно запустить отвалившуюся формулу не получится, вместо значения будет гордо красоваться пустая ячейка.
Чаще всего эти ошибки возникают точечно, и почти всегда помогает еще раз загрузить таблицу — данные подтянутся.
Но иногда вылезают совсем интересные баги. Например, в формуле, которая ссылается на упавшую ячейку, появлялся #REF! (как при удалении ячейки), убивая содержимое этой формулы. То есть вместо формулы появляется постоянное (текстовое) значение, которое нужно убирать вручную.
Возможные решения
Опытным путем мы выяснили, что проблемы начинаются, когда в одной таблице появляется больше 300 формул с IMPORTRANGE на разные файлы.
Есть подозрение, что проблема — в большом количестве обращений к таблицам из одного места. Похожих проблем, когда таблица обращается к меньшему количеству файлов, но несколько раз, мы не нашли. Но возможно, там тоже есть что-то подобное.
Если ссылаться на один файл из разных мест — такая ошибка не появляется.
Вариант решения. Если количество таблиц уменьшить невозможно, попробуйте собрать первоначальную информацию в промежуточный файл. Так можно распределить обращения к файлам и не биться головой в установленный потолок.
Часть автоматизации задачника выполняется на базе Google AppScripts — облачной песочницы с JS-based языком. Она позволяет работать с таблицами (и другими продуктами Google) вне их графической оболочки и автоматизировать рутинные процессы.
Хотя сервис очень мощный, на технические ограничения мы наткнулись практически сразу, как начали его использовать. Часть из них явно ввели намеренно, но некоторые — похожи на недоработки, и хочется надеяться, что когда-нибудь их поправят.
Скрипт выполняется только 30 минут. Иногда чуть больше, но мы списали это на погрешность времени запроса к файлам. Когда скрипт отработал полчаса — он просто останавливается, а в консоли появляется соответствующая ошибка. Если скрипт перезапустить, он начнет работу с начала. Возможности перезапустить скрипт и продолжить выполнение мы не нашли.
Это нужно, очевидно, чтоб убивать случайно запущенные бесконечные скрипты. Ну и чтобы не было соблазна писать на скриптах огромные программы. Так или иначе, ограничение приходится учитывать.
Интересно то, что и из этого правила есть исключение. Однажды скрипт проработал почти 44 минуты и даже успешно выполнился. Но он такой был один, поэтому мы решили, что ему просто повезло.
Вариант решения. Если очень сильно заморочиться, то можно сохранять в служебной таблице текущее состояние скрипта. При запуске проверять, что он уже сделал, и запускать с нужного места.
Чтобы уложиться в ограничение по времени выполнения, приходится делать пробные запуски и оценивать время выполнения скрипта.
Сложность в том, что запросы к файлам и дальнейшая работа с ними занимают разное время. Один запрос может выполняться с вилкой в 1 секунду. Иногда (видимо, при большой нагрузке на сервер) бывает и больше, но это исключение. Получается, что 500 запросов к документам могут выполняться как 250 секунд, так и 750.
Вдобавок скорость загрузки данных из документа зависит от его объема: размера таблиц, объема данных и дополнительных данных таблиц (правил, скриптов и т.д.).
В задачнике студенческие таблицы одинаковы по размеру, а объем данных меняется в рамках погрешности. Но это стоит учитывать, если вы работаете с разноплановыми документами.
Варианты решения.
Между выполнениями интервал 1 час
Выше мы уже рассказывали при ошибке importrange вместо формулы подставляется #REF!. Немного покопались в мануалах и нашли там возможность на AppScripts написать собственную формулу. Заподозрили, что формулы встроенные тоже работают на скриптах. Но эта мысль скорее для фанатов теории заговора.
Так или иначе, иногда скрипт просто отваливается посреди выполнения. Объясняет свое поведение двумя причинами:
Эти ошибки появляются настолько рандомно, что найти их причину невозможно. У нас параллельно запущено пять скриптов для разных потоков студентов, и, возможно, иногда это вызывает вторую ошибку. Но в 95% выполнений все проходит отлично при тех же вводных. Первая ошибка — вообще загадка.
Интересно, что если скрипт не использует формулу, то он не убивает неполученные данные, а возвращает пустую строку. Мы предусмотрели это, и если скрипт получает пустые данные, он просто пропускает эту итерацию, оставляя предыдущее значение.
Можно было сделать и повторный запрос, но:
Варианты решения. Никаких. Просто жаловаться на Google в профильных ветках и учитывать эти особенности при разработке нагруженных скриптов.
Самый редкий кейс — в AppScripts при работе с таблицами нельзя удалить правило условного форматирования. Можно создать, изменить, применить к диапазону. Удалить — нет.
А так как у нас на форматировании построена немалая часть задачника, получилось особенно больно.
Похожая история и с правилами проверки данных, но там еще хуже — их нельзя даже редактировать. Только танец с бубном в виде создания изменяемой копии правила.
Вариант решения. Удалите из правила все диапазоны, для которых оно применяется. Плюсы: правило больше не будет применяться. Минусы: вы намусорили в таблице.
No-code в нашем случае отлично показал себя. Он кратно удешевляет создание MVP и первых версий продуктов и позволяет любому члену команды создавать новые фичи. Но это не волшебная таблетка, которая все сделает за вас, и технические проблемы все равно придется решать вручную.
Уверены, ограничений и недоработок у Google кратно больше. Уверены, что часть наших проблем уже кто-то решил. Уверены, что с оставшимися вполне можно жить.
Но раз со сложностями столкнулись мы, то могут и другие. Надеемся, этот текст поможет кому-то еще найти обходное решение или не повторять наших ошибок.
8
нормальное число, чего вы