Reports in their own thread

I have a couple general questions about reports, wondering if anyone has encountered these before.

  1. If I have a report, with 2 report schedules with email actions at the same time, are these reports executed and distributed on their own thread?

  2. Is there any way, in scripting, to call something like system.report.executeAndDistribute in its own thread? The docs say system.report.executeAndDistribute() does not run on its own thread and can get blocked.

Thanks in advance!

That’s what invokeAsynchronous is for. Not just for reporting.

1 Like

The reason I ask is since the executeAndDistribute docs explicitly state it runs on a shared thread I was wondering if it would even work to call system.util.invokeAsynchronous. Perhaps all that would do is asynchronously invoke executeAndDistribute which would place the report in some kind of que on a shared thread and still have the same blocking problem?

Per the manual:

the given function will start executing asynchronously on a different thread.

executeAndDistribute() itself will not return to its caller until complete or failed.

If in doubt, you can also subclass java.lang.Runnable, implement your code as the run() method, then create and start a java.lang.Thread with that runnable. This latter approach allows you to name the thread for less cryptic gateway monitoring.

I was thinking for some reason executeAndDistribute returned immediately because it returned nothing. I just did a test and it behaves how you described when I call invokeAsynchronous. Thanks!

I thought it was working initially until I did this test.

from functools import partial
from system.report import executeAndDistribute

path = "Development/Timing"
project = "Reports"
action = "email"
actionSettings = {
	"smtpServerName": "SMTP1_1",
	"from": "noreply@tanklogix.com",
	"to": ["salbrechtsen@tanklogix.com"],
	"subject": "Timing Report",
	"fileType": "pdf",
	"attachmentName": "report.pdf"
}

parameters = {
	"SleepSeconds": 60
}
system.util.invokeAsynchronous(partial(executeAndDistribute, path, project, parameters, action, actionSettings))

for i in range(3):
	parameters = {
		"SleepSeconds": 0
	}
	actionSettings["subject"] = "Timing Report %i" % i
	system.util.invokeAsynchronous(partial(executeAndDistribute, path, project, parameters, action, actionSettings))

The timing report just does a time.sleep() using the SleepSeconds parameter in a script, and then prints out the start and end time of the report. TimingReport.proj (6.6 KB)

I expected to get 3 emails with the subjects “Timing Report 0”, “Timing Report 1”, and “Timing Report 2”. Then ~1 minute later another email with the subject “Timing Report”. The emails came in with the correct timing and contents, however, all 4 subject lines read “Timing Report 4”. On running this a few times, I got a variety of email subjects.

It appears there are race conditions when calling executeAndDistribute with invokeAsynchronous. Doing this does not appear to be thread safe. It appears each report can only execute one action at a time and it is a shared resource. This is probably why IA docs state the possibility of blocking on execute and distribute, it has to wait for the last action to finish, otherwise it will be overwritten.

Next, I’m going to try calling system.report.executeReport asynchronously and sending my own email with system.net.sendEmail when I get the report bytes back.

You re-used actionSettings, so every execution got whatever the subject key held at the time it looked for each phase of the report. There is overhead starting a new thread, which prevented the latter threads from catching the correct subject. I’m not sure how you got “Timing Report 4”.

These race conditions are on you. Don’t re-use lists or dictionaries in multiple threads, unless you are using them to communicate between threads.

Nice catch! I didn’t think about python essentially passing by reference there. Made sure I was giving it a new actionSettings each time and it seems to be working.