Second Repeating_Panel (data_grid) populated by server calls to a different datatable for all items with that equipment name (row) to get the latest inspection record of that item of equipment to populate the DataGrid.
This is perhaps a workaround but you could move the work to a background task that would email you the PDF after it was generated.
This would make it so the user couldn’t do a spot check to make sure things looked ok though. You could get around that by perhaps showing the first 10 rows to the user (or a sample of them) and have the user double check before launching the background task.
Alternatively, launch the background task and have the task store the results somehow (as a blob in a separate data table perhaps). Then periodically check the task, and when completed, display the data. You could make a separate scheduled task to clean up old queries.
Exception: PDF generation failed: Components did not load within allowed time.
I’ve tried storing the list of dictionaries to populate the DataGrid as a Simple Object within a DataTable. This also took too long to load and timed out.
I know I could split it down into multiple documents but wanted a flowing PDF document rather than having gaps and white space where I have had to implement a split.
You’re doing a lot of nested searches, and they’re taking a long time
You’re doing it all from inside the PDF renderer (which is a headless Chrome browser that’s a bit of a resource hog, so we don’t let it run longer than 30s)
We can address those issues separately. #2 will be the fastest, so let’s start there. You can precalculate the data before you call anvil.pdf.render_form(), and then pass it as an argument to the form’s constructor - that way, you can calculate what you’re displaying on the server (which is faster). What’s more, you could calculate it in a Background Task (which gives you all the time in the world), and then call the PDF renderer once you’ve assembled your report.
This should get you up and running while you optimise Issue #1, which is a little more tricky, as it relates to your actual search logic. For starters, the search goes faster if you do it from the server (you’re closer to the database!), but also, this seems odd to me:
Did you mean Kit_Item= to be an argument to tables.order_by() rather than search()? It’s possible you’re querying the whole inspection table, every time, for every item of kit, which could explain a bit of the slowness.
Explanation of #1. Each item of kit will have many inspections (these inspections are done every 6 months) so there are 3 DataTables to compile the PDF report.
Table 1: Kit_Info which details the make, model, shorthand identifier for that piece of equipment
Table 2: Kit_Item which details each item of that type of kit including serial numbers
Table 3: Inspection which details each time a specific item of kit is inspected
Therefore the reason for the nested search is to find the most recent inspection for a single piece of equipment.
I do not have a solution around that except for a search for that piece of equipment and order the date descending, then taking the first result at the most recent inspection of that piece of equipment.
Have I missed something in my methods or does that now make sense?
I’ve just re-read my original post realised that I pasted the wrong app_tables search into the original post. Correct version (as per the clone link):
This is a case where using SQL you get all you need in one shot and in the correct order. And it’s really fast.
It is only available with dedicated plans (like mine ).
Are you precalculating in an ordinary server call, or in a background task? You should be able to avoid timeouts by doing the precalc in a background task (which can run as long as you like), and then rendering it to PDF (which will then be quick!)
I’m pre-calculating using a background task and saving the data in a DataTable.
Then separately calling the DataTable and passing it to the form.
@anvil.server.callable
def run_pdf():
print("start")
data = app_tables.reportstore.search()[0]
pdf = anvil.pdf.render_form('Form1',data['Data'])
create_inspection_pdf(pdf) # email pdf form
print("email sent")
I had a quick look and tried to load form1 without rendering to pdf and it still takes around 100 seconds to load without any server calls … (pre copying the data as a list)… since the rendered form can’t take longer than 30 seconds I think you’ll need to ensure that the form itself takes less time to load in order to be rendered.
perhaps using the renderform isn’t the right approach here? The dataset seems too large… how many nested rows are loaded to the form?
perhaps you could use one of the pdf writers from the list of packages https://anvil.works/docs/server/packages. You can then keep all this in a background task… use a progress bar so that the user has an idea of how long it will take…
Hi Meredydd, is this a limitation of Anvil loading repeating panels and I should attempt a different method or is this something that can be sped up to use the Anvil PDF function?