Esempio n. 1
0
  def Execute(self, operation_id=None, wait_callback=None):
    """Starts execution of all operations for the managed user. Once all operations have been
    completed, or if another server is already executing the operations, then the callback
    passed to __init__ is invoked. If the "operation_id" argument is provided, it is used as a
    hint as to where to start execution. However, if an operation with a lower id is found in
    the database, that is executed first, in order to ensure that the server executes operations
    in the same order that a device submitted them. If "wait_callback" is specified, then it is
    invoked when the "operation_id" operation is complete (but other operations for the user may
    still be running). If "operation_id" is None in this case, then "wait_callback" will only be
    invoked once all operations for this user are complete.
    """
    def _OnCompletedOp(type=None, value=None, tb=None):
      """Wraps the caller's callback so that it is called in the original context, and any
      exception is raised in the original context.
      """
      if (type, value, tb) != (None, None, None):
        raise type, value, tb

      wait_callback()

    @gen.engine
    def _ExecuteAll():
      """Executes all ops within the scope of an OpContext. "yield" is not supported in the
      static scope of OpContext, which is why this is a separate function.
      """
      try:
        self._is_executing = True
        self._requery = True
        while self._requery:
          yield self._ExecuteAll(operation_id=operation_id)
      finally:
        # Notify any remaining listeners that their operations are complete (since all operations are now complete).
        for cb_op_id in self._sync_cb_map.keys():
          self._InvokeSyncCallbacks(cb_op_id)

        # Complete execution.
        self._is_executing = False
        self._callback()

    # Add callbacks for synchronous case.
    if wait_callback is not None:
      self._sync_cb_map[operation_id].append(stack_context.wrap(_OnCompletedOp))

    if not self._is_executing:
      # Establish op context, and then call another func, since it is not safe to use a yield in the static scope
      # of the "with stack_context" statement. 
      with stack_context.StackContext(OpContext()):
        _ExecuteAll()
    else:
      # Sets flag so that once all operations are executed, the list of operations is re-queried
      # in order to find any newly added operations.
      self._requery = True