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....."