Understanding sendRequestAsync

There's no RPC involved. Your script is starting on the gateway and ending on the gateway - that's a fundamental piece of the architecture of Perspective. Under the hood, we're using a websocket to shuttle all property values from the gateway/backend to your frontend session in the user agent, but you have no control over that, and nothing you're doing with arbitrary code (scripts, expressions) is running in the frontend in Perspective.

What I'm recommending is basically equivalent to what you have, you just get to define all the logic in one place (either in your script directly or, as Phil will recommend, in the project library) - and has the benefit of being able to send arbitrary data through to the callback without serialization overhead. The only thing the below example doesn't do is timeout automatically after a few seconds. If I had to do that, I'd look into Java's CompletableFuture API to 'chain' my actions together; it's not quite worth it IMO for the basic example here but incredibly powerful for composing asynchronous stuff together; see this post for some context to get started.

def runAction(self, event):	
	def successFunc(response):
		logger = system.util.getLogger("AsyncSuccess")
		logger.info("Success callback triggered with response: %s" % str(response))
		
		self.getSibling("status").props.text = "Updated!"
		self.getSibling("Table").refreshBinding("props.data")

	def errorFunc(error):
		logger = system.util.getLogger("AsyncError")
		logger.error("Error callback triggered: %s" % str(error))
		
		self.getSibling("status").props.text = "Error!"

	def callback(payload):
		import time
		
		logger = system.util.getLogger("TestHandler")
		
		try:
			# Add a 3-second delay
			logger.info("Starting 3-second delay")
			time.sleep(3)
			logger.info("Delay complete, processing payload")
			
			# Process the payload
			inputValue = payload.get("A")
			if inputValue == 10:  # Simulate success
				successFunc({"result": "Success, received A = %s" % inputValue})
			else:  # Simulate error
				errorFunc(Exception("Invalid input value"))
		except Exception as e:
			logger.error("Error in handler: %s" % str(e))
			errorFunc(e)

	# Define the payload
	payload = {
		"A": 10
	}
	
	# Clean the table
	self.getSibling("Table").props.data = []
	
	# Asynchronous request
	logger = system.util.getLogger("SendRequestAsync")
	logger.info("Sending async request")
	system.util.invokeAsynchronous(callback, args=[payload])
	
	self.getSibling("status").props.text = "Refreshing....."
2 Likes