Blog · usługi programistyczne

Kłódka na arkuszu – dlaczego Twoja aplikacja Apps Script zaczyna się wieszać

2026-09-14

Objaw: aplikacja Apps Script zamula przy wielu użytkownikach

Aplikacja napisana w Google Apps Script działa przy jednej osobie idealnie. Dodajesz drugą, trzecią, piątą – i zaczyna się dziać coś dziwnego. Kliknięcie zapisu kręci się trzy sekundy. Potem dziesięć. Ktoś próbuje wgrać większą paczkę plików i cała aplikacja zamiera na minutę. Formularz się nie zapisuje, przycisk mieli, a użytkownik nie wie, czy operacja przeszła, czy nie.

Kod nie jest zły. Nic nie zmieniałaś od miesięcy. Po prostu firma urosła i coraz więcej osób pracuje na aplikacji jednocześnie. I nagle to, co szło jak burza, zaczyna się wlec.

Co się dzieje pod maską

Google Sheets w roli bazy ma jedno założenie, które nie jest błędem, tylko konsekwencją tego, czym on w ogóle jest: to arkusz, nie baza. Żeby dwie osoby jednocześnie edytujące ten sam plik widziały spójne dane, silnik trzyma globalną kłódkę na cały arkusz w momencie zapisu.

W praktyce oznacza to: gdy jeden skrypt pisze do arkusza, wszystkie inne skrypty próbujące zapisać coś w tym samym arkuszu czekają w kolejce. Nie wywalają się z błędem, nie idą równolegle – po prostu stoją, aż wcześniejszy skończy.

Przy jednej osobie i pięciu zapisach dziennie to jest niewidzialne. Przy dwudziestu osobach, które robią po dwadzieścia operacji na godzinę, matematyka staje się bezlitosna. Jeśli jeden zapis trwa 2 sekundy, dziesięć zapisów w kolejce to 20 sekund oczekiwania dla ostatniego. A aplikacja użytkownikowi wygląda po prostu jak zawieszona.

Dlaczego „przyspieszanie kodu” nie pomaga

Naturalnym odruchem jest optymalizacja: batchowanie zapisów, cache, ograniczanie liczby wywołań getRange. To wszystko jest dobre i warto – ale nie usuwa przyczyny. Skracasz każdy pojedynczy zapis z 2 sekund do 0,8 – a kłódka wciąż jest, kolejka wciąż się buduje, tylko wolniej.

To jest różnica jakościowa, nie ilościowa. Jeden pas ruchu na moście nie stanie się dwoma dlatego, że samochody jeżdżą trochę szybciej.

Co realnie można zrobić

Trzy uczciwe opcje, ustawione od najtańszej do najkosztowniejszej:

1. Odsunąć zapis w czasie (queue + trigger). Zamiast pisać do arkusza synchronicznie w momencie kliknięcia, wrzuć zdarzenie do kolejki (np. do PropertiesService) i pozwól triggerowi w tle spokojnie je przemielić. Użytkownik nie czeka, bo widzi natychmiast „zapisano”. Wada: nie działa dla operacji, w których użytkownik musi dostać wynik od razu (np. wygenerowany numer zamówienia).

2. Wyprowadzić najgorętsze tabele do prawdziwej bazy. Jeśli 80% zapisów dotyczy jednej-dwóch tabel (np. statusy zamówień), można zostawić resztę w arkuszu, a te dwie przenieść np. do Postgresa. Baza nie ma globalnego locka – dwie osoby mogą zapisywać jednocześnie do różnych wierszy. Skomplikowane, bo aplikacja musi umieć czytać z obu miejsc, ale najczęściej najbardziej opłacalne.

3. Przenieść całą warstwę danych. Arkusz zostaje tylko jako narzędzie do wglądu i ręcznych korekt dla właściciela, a aplikacja żyje w prawdziwej bazie. Największa robota, ale też jedyna droga jeśli aplikacja ma jeszcze rosnąć.

Jak wybrać między 1, 2 i 3?

- do 10 aktywnych użytkowników        → opcja 1 zwykle wystarcza
- 10-30 użytkowników, kilka gorących tabel                              → opcja 2 to najlepszy stosunek nakładu do efektu
- powyżej 30, albo aplikacja rośnie   → opcja 3, i im wcześniej,
                                         tym mniej boli

Jeśli chcesz zobaczyć, jak krok po kroku przeprowadzić migrację z arkusza do Postgresa bez zatrzymywania firmy, opisałam ten wzorzec osobno w artykule Dual-write – jak przenieść aplikację na nową bazę bez przestoju (dostępny od 22.09), wraz z kodem dla Apps Script + Supabase.

Czego nie robić

Nie rzucaj się od razu do przepisywania wszystkiego w Node/Django/cokolwiek. To pułapka. Aplikacja na arkuszu ma jedną olbrzymią zaletę – klient sam sobie może w nim grzebać. Cofnąć zmianę, sprawdzić dane, wyeksportować do Excela na spotkanie. Odbierając mu arkusz, odbierasz mu też ten komfort. Migracja ma sens dopiero wtedy, gdy koszt „zamulania” przekroczył koszt „utraty arkusza jako narzędzia”.

I nie próbuj obejść kłódki przez LockService.getScriptLock(). To jest inne narzędzie do innego problemu (chroni Twój kod przed sobą samym), a globalnej kłódki na arkusz nie ruszy.

Czego się nauczyłam

Google Apps Script to świetne narzędzie do budowania czegoś, co szybko musi zacząć działać dla małego zespołu. Ale ma sufit i lepiej wiedzieć, gdzie ten sufit jest, zanim się w niego uderzy. „Zamulanie” nie jest bugiem do naprawienia – to sygnał, że aplikacja przerosła platformę. Rozpoznanie tego sygnału i zaproponowanie klientowi rozsądnej ścieżki wyjścia, zanim będzie tracić na tym pieniądze, jest połową wartości, jaką się jako programistka wnosi.

Wróć do wszystkich wpisów

Masz projekt do omówienia?

Napisz, o co chodzi - nie musi być technicznie, od tego jestem ja. Odezwę się i powiem wprost, czy i jak mogę pomóc.