From 23aa762be201bedb2e997aca627f12c2968d7487 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 16 Aug 2024 14:33:23 +1000 Subject: [PATCH] Add fallback report loading in case websockets fail This also resolves a race condition scenario. Even if the report gets rendered via websockets before the controller response is rendered then the fallback script loads the report again. It's not the most beautiful but probably okay until we replace websockts altogether. I'm leaving websockets in at the moment because it can render the report much quicker than polling can. --- app/controllers/admin/reports_controller.rb | 4 +- .../admin/reports/_fallback_display.html.haml | 44 +++++++++++++++++++ .../admin/reports/create.turbo_stream.haml | 1 + spec/system/admin/reports_spec.rb | 2 - 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 app/views/admin/reports/_fallback_display.html.haml diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index eaf9be5895..fe8a1874c1 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -58,12 +58,12 @@ module Admin end def render_in_background - blob = ReportBlob.create_for_upload_later!(report_filename) + @blob = ReportBlob.create_for_upload_later!(report_filename) ReportJob.perform_later( report_class:, user: spree_current_user, params:, format: report_format, - blob:, + blob: @blob, channel: ScopedChannel.for_id(params[:uuid]), ) end diff --git a/app/views/admin/reports/_fallback_display.html.haml b/app/views/admin/reports/_fallback_display.html.haml new file mode 100644 index 0000000000..1538794665 --- /dev/null +++ b/app/views/admin/reports/_fallback_display.html.haml @@ -0,0 +1,44 @@ +.download.hidden + = link_to t("admin.reports.download.button"), file_url, target: "_blank", class: "button icon icon-file" + +:javascript + (function () { + const tryDownload = function() { + const link = document.querySelector(".download a"); + + // If the report was already rendered via web sockets: + if (link == null) return; + + fetch(link.href).then((response) => { + if (response.ok) { + response.blob().then((blob) => blob.text()).then((text) => { + const loading = document.querySelector(".loading"); + + if (loading == null) return; + + loading.remove(); + document.querySelector("#report-go button").disabled = false; + + if (link.href.endsWith(".html")) { + // This replaces the hidden download button with the report: + link.parentElement.outerHTML = text; + } else { + // Or just show the download button when it's ready: + document.querySelector(".download").classList.remove("hidden") + } + }); + } else { + setTimeout(tryDownload, 1000); + } + }); + } + + /* + A lot of reports are rendered within 250ms. Others take at least + 2.5 seconds. There's a big gap in between. Observed on: + https://openfoodnetwork.org.au/admin/sidekiq/metrics/ReportJob?period=8h + https://openfoodnetwork.org.uk/admin/sidekiq/metrics/ReportJob?period=8h + https://coopcircuits.fr/admin/sidekiq/metrics/ReportJob?period=8h + */ + setTimeout(tryDownload, 250); + })(); diff --git a/app/views/admin/reports/create.turbo_stream.haml b/app/views/admin/reports/create.turbo_stream.haml index 620d795b24..ecfa4f13a0 100644 --- a/app/views/admin/reports/create.turbo_stream.haml +++ b/app/views/admin/reports/create.turbo_stream.haml @@ -2,4 +2,5 @@ = button t(:go), "report__submit-btn", "submit", disabled: true = turbo_stream.update "report-table" do = render "admin/reports/loading" + = render "admin/reports/fallback_display", file_url: @blob.expiring_service_url = turbo_stream.scroll_into_view("#report-table", behavior: "smooth") diff --git a/spec/system/admin/reports_spec.rb b/spec/system/admin/reports_spec.rb index b0ef194e70..62de258992 100644 --- a/spec/system/admin/reports_spec.rb +++ b/spec/system/admin/reports_spec.rb @@ -115,8 +115,6 @@ RSpec.describe ' end it "allows the report to finish before the loading screen is rendered" do - pending "Race condition between loading message and report rendering" - login_as_admin visit admin_report_path(report_type: :customers)