fix(raport_slotow): strumieniowy eksport XLSX + limit wierszy (2.7)#652
Open
mpasternak wants to merge 2 commits into
Open
fix(raport_slotow): strumieniowy eksport XLSX + limit wierszy (2.7)#652mpasternak wants to merge 2 commits into
mpasternak wants to merge 2 commits into
Conversation
…2.7) MyTableExport.export_xlsx trzymał trzy kopie datasetu w RAM naraz (tablib.Dataset -> openpyxl.Workbook -> bytes z NamedTemporaryFile) bez limitu wierszy, synchronicznie w cyklu request/response -> ryzyko OOM/DoS przy dużym eksporcie (poz. 2.7 audytu). Wzorzec z bpp/views/mymultiseek.py (limit + strumieniowanie): - Pomijamy budowę pełnego tablib.Dataset — strumieniujemy table.as_values() (generator) prosto do openpyxl (jedna kopia mniej). - NamedTemporaryFile (round-trip przez dysk) zastąpione io.BytesIO. - Limit RAPORT_SLOTOW_EXPORT_MAX_ROWS=10000 sprawdzany PRZED iteracją przez len(table.rows) (COUNT, bez materializacji). Przekroczenie -> wyjątek ExportRowLimitExceeded łapany na granicy widoku i zamieniany na HTTP 400 z czytelnym komunikatem (bez cichego ucięcia). Objęte ścieżki synchroniczne: autor, ewaluacja, zerowy, upowaznienie_pbn. Raport uczelniany (generacja async przez liveops/celery) ma bramkę wierszy wyłączoną (export_max_rows=None), zachowuje zachowanie, korzysta z odchudzonego budowania. Zawartość i format pliku XLSX bez zmian — zmienia się tylko sposób budowy. Testy charakteryzacyjne pinują zawartość komórek; nowe testy sprawdzają zadziałanie limitu (bez porównywania bajtów — niedeterministyczny dcterms:created). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019GmViAsaif9MXeuDMA5NHX
Recenzja wskazała utajoną krawędź: len(self.table.rows) daje COUNT tylko dla tabeli paginowanej; bez paginatora degraduje do len(self.data) = pełna materializacja przed bramką, niwecząc ochronę OOM. Wszystkie obecne widoki z max_rows są paginowane; dopisano ostrzeżenie dla przyszłych. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019GmViAsaif9MXeuDMA5NHX
| try: | ||
| return exporter.response(filename=self.get_export_filename(export_format)) | ||
| except ExportRowLimitExceeded as e: | ||
| return HttpResponseBadRequest(str(e)) |
| filename=self.get_export_filename(export_format, n) | ||
| ) | ||
| except ExportRowLimitExceeded as e: | ||
| return HttpResponseBadRequest(str(e)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Eksport XLSX materializował cały dataset, kopiował do
openpyxl, czytał jakobytes— trzy kopie w RAM, bez limitu wierszy, synchronicznie w cyklurequest/response. Ryzyko OOM/DoS (poz. 2.7 audytu).
Zmiana
Wspólny chokepoint
MyTableExport.export_xlsx(obejmuje ścieżki: autor,ewaluacja, zerowy, upowaznienie_pbn):
table.as_values()),io.BytesIOzamiastNamedTemporaryFile,COUNT-em przed iteracją; przekroczenie→
ExportRowLimitExceeded→ HTTP 400 z jasnym komunikatem (bez cichegoucięcia — reguła repo).
Zawartość XLSX niezmieniona (te same kolumny/dane/tabela/SUBTOTAL). Ścieżka async
(uczelnia, przez celery) nietknięta funkcjonalnie (bramka wyłączona
export_max_rows=None, ale korzysta z odchudzonego budowania).Zakres i follow-up
Odłożone jako inny wzorzec (nie ten sam chokepoint):
nowe_raporty(flexible_reports databook) i
ewaluacja_optymalizacja/exports.py(openpyxlwprost + ZIP). FOLLOW-UP (znaleziony w review, poza zakresem): eksport
szczegółów uczelni biegnie synchronicznie BEZ limitu — potencjalnie największa
powierzchnia OOM, do osobnej decyzji (bramka albo tło).
Weryfikacja
test_export_xlsx.py12 passed (charakteryzacyjne + limit), selekcja 172 passed.dcterms:created).async nietknięty). Dopisany komentarz: bramka zależy od paginacji tabeli.
Poz. 2.7 audytu.
🤖 Generated with Claude Code
https://claude.ai/code/session_019GmViAsaif9MXeuDMA5NHX