code: def execute(self, *args, **kwargs):
          
          timeout = kwargs.pop("timeout", -1)
          execute_async = kwargs.pop("run_async", False)
          result = None
          if self._action_lock.acquire(False):
              try:
                  self.spine.trigger_event("actionStarted", self.action_id)
                  if timeout == -1 and not execute_async:
                      result = self._execute(*args, **kwargs)
                  else:
                      thread = _ActionThread(self, args, kwargs)
                      thread.start()
                      if not execute_async:
                          thread.join(timeout)
                          if thread.is_alive():
                              result = None
                              #self._send_message("failed", "Timedout in call to action")                
                              raise TimeoutError("Timeout in call to action: " + self.action_id)
                          else:
                              result = thread.result
                      else:
                          result = thread
                  return result
              except Exception as ex:
                  print(ex)
                  self._action_lock.release()
              finally:
                  pass
              #    self._action_lock.release()
          else:
              if not self._action_lock.acquire(True, timeout):
                  return None
              self._action_lock.release()
              return self._last_result
docs: Executes the action and returns the result. 
              You dont have to call this function directly as the class is callable (implements __call__)
              you just call the @action marked function as normal.
  
              @action
              def my_action(p1)
                  print(p1)
  
              my_action("x")