Example #1
0
            public async Task SignalAsync(WorkflowExecution execution, string signalName, params object[] args)
            {
                await SyncContext.Clear;

                var dataConverter = Activity.Client.DataConverter;

                await Activity.Client.SignalWorkflowAsync(execution, signalName, CadenceHelper.ArgsToBytes(dataConverter, args));
            }
Example #2
0
        /// <summary>
        /// Internal constructor for use outside of a workflow.
        /// </summary>
        /// <param name="client">Specifies the associated client.</param>
        /// <param name="execution">Specifies the target workflow execution.</param>
        /// <param name="domain">Optionally specifies the target domain (defaults to the client's default domain).</param>
        internal ExternalWorkflowStub(CadenceClient client, WorkflowExecution execution, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(client != null, nameof(client));
            Covenant.Requires <ArgumentNullException>(execution != null, nameof(execution));

            this.client    = client;
            this.domain    = client.ResolveDomain(domain);
            this.Execution = execution;
        }
Example #3
0
        /// <summary>
        /// Used to construct an untyped workflow stub that can manage an existing external workflow.
        /// </summary>
        /// <param name="client">The associated client.</param>
        /// <param name="execution">The workflow execution.</param>
        /// <param name="withinWorkflow">
        /// Optionally indicates that the stub was created from within a workflow and that
        /// operations such as get result, query, signal, and cancel must be performed
        /// within local activities such that that can be replayed from history correctly.
        /// </param>
        internal WorkflowStub(CadenceClient client, WorkflowExecution execution, bool withinWorkflow = false)
        {
            Covenant.Requires <ArgumentNullException>(client != null, nameof(client));
            Covenant.Requires <ArgumentNullException>(execution != null);

            this.client         = client;
            this.Execution      = execution;
            this.withinWorkflow = withinWorkflow;
        }
Example #4
0
        /// <summary>
        /// Creates an untyped stub for a known workflow execution.
        /// </summary>
        /// <param name="execution">The workflow execution.</param>
        /// <returns>The <see cref="WorkflowStub"/>.</returns>
        /// <remarks>
        /// Unlike activity stubs, a workflow stub may only be used to launch a single
        /// workflow.  You'll need to create a new stub for each workflow you wish to
        /// invoke and then the first method called on a workflow stub must be
        /// the one of the methods tagged by <see cref="WorkflowMethodAttribute"/>.
        /// </remarks>
        public WorkflowStub NewUntypedWorkflowStub(WorkflowExecution execution)
        {
            Covenant.Requires <ArgumentNullException>(execution != null, nameof(execution));
            EnsureNotDisposed();

            return(new WorkflowStub(this)
            {
                Execution = execution
            });
        }
Example #5
0
        /// <summary>
        /// Internal constructor for use within a workflow.
        /// </summary>
        /// <param name="parentWorkflow">Specifies the parent workflow.</param>
        /// <param name="execution">Specifies the target workflow execution.</param>
        /// <param name="domain">Optionally specifies the target domain (defaults to the client's default domain).</param>
        internal ExternalWorkflowStub(Workflow parentWorkflow, WorkflowExecution execution, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(parentWorkflow != null, nameof(parentWorkflow));
            Covenant.Requires <ArgumentNullException>(execution != null, nameof(execution));

            this.parentWorkflow = parentWorkflow;
            this.client         = parentWorkflow.Client;
            this.domain         = client.ResolveDomain(domain);
            this.Execution      = execution;
        }
Example #6
0
        /// <summary>
        /// Creates a typed workflow stub connected to a known workflow execution
        /// using a <see cref="WorkflowExecution"/>.  This can be used to signal and
        /// query the workflow via the type-safe interface methods.
        /// </summary>
        /// <typeparam name="TWorkflowInterface">Identifies the workflow interface.</typeparam>
        /// <param name="execution">Specifies the <see cref="WorkflowExecution"/>.</param>
        /// <returns>The dynamically generated stub that implements the workflow methods defined by <typeparamref name="TWorkflowInterface"/>.</returns>
        /// <remarks>
        /// Unlike activity stubs, a workflow stub may only be used to launch a single
        /// workflow.  You'll need to create a new stub for each workflow you wish to
        /// invoke and then the first method called on a workflow stub must be
        /// the one of the methods tagged by <see cref="WorkflowMethodAttribute"/>.
        /// </remarks>
        public TWorkflowInterface NewWorkflowStub <TWorkflowInterface>(WorkflowExecution execution)
            where TWorkflowInterface : class
        {
            Covenant.Requires <ArgumentNullException>(execution != null, nameof(execution));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(execution.WorkflowId), nameof(execution.WorkflowId));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(execution.RunId), nameof(execution.RunId));
            CadenceHelper.ValidateWorkflowInterface(typeof(TWorkflowInterface));
            EnsureNotDisposed();

            return(StubManager.NewWorkflowStub <TWorkflowInterface>(this, execution.WorkflowId, execution.RunId));
        }
Example #7
0
        /// <summary>
        /// Used to construct an untyped workflow stub that can be used to start an external workflow.
        /// </summary>
        /// <param name="client">The associated client.</param>
        /// <param name="workflowTypeName">The workflow type name.</param>
        /// <param name="execution">The workflow execution.</param>
        /// <param name="options">The workflow options.</param>
        internal WorkflowStub(CadenceClient client, string workflowTypeName, WorkflowExecution execution, WorkflowOptions options)
        {
            Covenant.Requires <ArgumentNullException>(client != null, nameof(client));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(workflowTypeName));
            Covenant.Requires <ArgumentNullException>(execution != null);
            Covenant.Requires <ArgumentNullException>(options != null);

            this.client           = client;
            this.WorkflowTypeName = workflowTypeName;
            this.Execution        = execution;
            this.Options          = options;
            this.withinWorkflow   = false;
        }
        /// <summary>
        /// <para>
        /// Cancels a workflow if it has not already finished.
        /// </para>
        /// <note>
        /// Workflow cancellation is typically considered to be a normal activity
        /// and not an error as opposed to workflow termination which will usually
        /// happen due to an error.
        /// </note>
        /// </summary>
        /// <param name="execution">Identifies the running workflow.</param>
        /// <param name="domain">Optionally identifies the domain.  This defaults to the client domain.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="CadenceEntityNotExistsException">Thrown if the workflow no longer exists.</exception>
        /// <exception cref="CadenceBadRequestException">Thrown if the request is invalid.</exception>
        /// <exception cref="CadenceInternalServiceException">Thrown for internal Cadence problems.</exception>
        internal async Task CancelWorkflowAsync(WorkflowExecution execution, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(execution != null);

            var reply = (WorkflowCancelReply) await CallProxyAsync(
                new WorkflowCancelRequest()
            {
                WorkflowId = execution.WorkflowId,
                RunId      = execution.RunId,
                Domain     = ResolveDomain(domain)
            });

            reply.ThrowOnError();
        }
Example #9
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="client">The associated client.</param>
        /// <param name="workflowTypeName">The workflow type name.</param>
        /// <param name="execution">The workflow execution or <c>null</c> if the workflow hasn't been started.</param>
        /// <param name="taskList">Specifies the task list.</param>
        /// <param name="options">Specifies the workflow options.</param>
        /// <param name="domain">Specifies specifies the domain.</param>
        internal WorkflowStub(CadenceClient client, string workflowTypeName, WorkflowExecution execution, string taskList, WorkflowOptions options, string domain)
        {
            Covenant.Requires <ArgumentNullException>(client != null);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(workflowTypeName));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(taskList));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(domain));

            this.client           = client;
            this.WorkflowTypeName = workflowTypeName;
            this.Execution        = execution;
            this.taskList         = taskList;
            this.Options          = options;
            this.domain           = domain;
        }
        /// <summary>
        /// Transmits a signal to a running workflow.
        /// </summary>
        /// <param name="execution">The <see cref="WorkflowExecution"/>.</param>
        /// <param name="signalName">Identifies the signal.</param>
        /// <param name="signalArgs">Optionally specifies the signal arguments as a byte array.</param>
        /// <param name="domain">Optionally specifies the domain.  This defaults to the client domain.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="CadenceEntityNotExistsException">Thrown if the workflow no longer exists.</exception>
        /// <exception cref="CadenceInternalServiceException">Thrown for internal Cadence problems.</exception>
        internal async Task SignalWorkflowAsync(WorkflowExecution execution, string signalName, byte[] signalArgs = null, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(execution != null);

            var reply = (WorkflowSignalReply) await CallProxyAsync(
                new WorkflowSignalRequest()
            {
                WorkflowId = execution.WorkflowId,
                SignalName = signalName,
                SignalArgs = signalArgs,
                RunId      = execution.RunId,
                Domain     = ResolveDomain(domain)
            });

            reply.ThrowOnError();
        }
        /// <summary>
        /// <para>
        /// Cancels a workflow if it has not already finished.
        /// </para>
        /// <note>
        /// Workflow termination is typically considered to be due to an error as
        /// opposed to cancellation which is usually considered as a normal activity.
        /// </note>
        /// </summary>
        /// <param name="execution">Identifies the running workflow.</param>
        /// <param name="reason">Optionally specifies an error reason string.</param>
        /// <param name="details">Optionally specifies additional details as a byte array.</param>
        /// <param name="domain">Optionally specifies the domain.  This defaults to the client domain.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="CadenceEntityNotExistsException">Thrown if the workflow no longer exists.</exception>
        /// <exception cref="CadenceBadRequestException">Thrown if the request is invalid.</exception>
        /// <exception cref="CadenceInternalServiceException">Thrown for internal Cadence problems.</exception>
        internal async Task TerminateWorkflowAsync(WorkflowExecution execution, string reason = null, byte[] details = null, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(execution != null);

            var reply = (WorkflowTerminateReply) await CallProxyAsync(
                new WorkflowTerminateRequest()
            {
                WorkflowId = execution.WorkflowId,
                RunId      = execution.RunId,
                Domain     = ResolveDomain(domain),
                Reason     = reason,
                Details    = details
            });;

            reply.ThrowOnError();
        }
        /// <summary>
        /// Returns the current state of a running workflow.
        /// </summary>
        /// <param name="execution">Identifies the workflow execution.</param>
        /// <param name="domain">Optionally specifies the domain.  This defaults to the client domain.</param>
        /// <returns>A <see cref="WorkflowDescription"/>.</returns>
        /// <exception cref="CadenceEntityNotExistsException">Thrown if the workflow no longer exists.</exception>
        /// <exception cref="CadenceBadRequestException">Thrown if the request is invalid.</exception>
        /// <exception cref="CadenceInternalServiceException">Thrown for internal Cadence problems.</exception>
        internal async Task <WorkflowDescription> GetWorkflowDescriptionAsync(WorkflowExecution execution, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(execution != null);

            var reply = (WorkflowDescribeExecutionReply) await CallProxyAsync(
                new WorkflowDescribeExecutionRequest()
            {
                WorkflowId = execution.WorkflowId,
                RunId      = execution.RunId,
                Domain     = ResolveDomain(domain)
            });

            reply.ThrowOnError();

            return(reply.Details.ToPublic());
        }
Example #13
0
        /// <summary>
        /// Starts the workflow, returning an <see cref="IAsyncFuture"/> that can be used
        /// to wait for the the workflow to complete and obtain its result.
        /// </summary>
        /// <typeparam name="TResult">The workflow result type.</typeparam>
        /// <param name="args">The workflow arguments.</param>
        /// <returns>An <see cref="ExternalWorkflowFuture{TResult}"/> that can be used to retrieve the workflow result as an <c>object</c>.</returns>
        /// <exception cref="InvalidOperationException">Thrown if the workflow has already been started.</exception>
        /// <remarks>
        /// <note>
        /// <b>IMPORTANT:</b> You need to take care to ensure that the parameters passed
        /// and the result type are compatible with the target workflow method.
        /// </note>
        /// </remarks>
        public async Task <ExternalWorkflowFuture <TResult> > StartAsync <TResult>(params object[] args)
        {
            await SyncContext.ClearAsync;

            Covenant.Requires <ArgumentNullException>(args != null, nameof(args));

            if (execution != null)
            {
                throw new InvalidOperationException("Cannot start a future stub more than once.");
            }

            execution = await client.StartWorkflowAsync(workflowTypeName, client.DataConverter.ToData(args), options);

            // Create and return the future.

            return(new ExternalWorkflowFuture <TResult>(client, execution));
        }
Example #14
0
        /// <summary>
        /// Returns the result from a workflow execution, blocking until the workflow
        /// completes if it is still running.
        /// </summary>
        /// <param name="execution">Identifies the workflow execution.</param>
        /// <param name="domain">Optionally specifies the domain.  This defaults to the client domain.</param>
        /// <returns>The workflow result encoded as bytes or <c>null</c>.</returns>
        /// <exception cref="EntityNotExistsException">Thrown if the workflow no longer exists.</exception>
        /// <exception cref="BadRequestException">Thrown if the request is invalid.</exception>
        /// <exception cref="InternalServiceException">Thrown for internal Cadence problems.</exception>
        internal async Task <byte[]> GetWorkflowResultAsync(WorkflowExecution execution, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(execution != null, nameof(execution));
            EnsureNotDisposed();

            var reply = (WorkflowGetResultReply) await CallProxyAsync(
                new WorkflowGetResultRequest()
            {
                WorkflowId = execution.WorkflowId,
                RunId      = execution.RunId,
                Domain     = ResolveDomain(domain)
            });

            reply.ThrowOnError();

            return(reply.Result);
        }
        /// <summary>
        /// Queries a workflow.
        /// </summary>
        /// <param name="execution">The <see cref="WorkflowExecution"/>.</param>
        /// <param name="queryType">Identifies the query.</param>
        /// <param name="queryArgs">Optionally specifies the query arguments encoded as a byte array.</param>
        /// <param name="domain">Optionally specifies the domain.  This defaults to the client domain.</param>
        /// <returns>The query result encoded as a byte array.</returns>
        /// <exception cref="CadenceEntityNotExistsException">Thrown if the workflow no longer exists.</exception>
        /// <exception cref="CadenceInternalServiceException">Thrown for internal Cadence problems.</exception>
        internal async Task <byte[]> QueryWorkflowAsync(WorkflowExecution execution, string queryType, byte[] queryArgs = null, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(execution != null);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(queryType));

            var reply = (WorkflowQueryReply) await CallProxyAsync(
                new WorkflowQueryRequest()
            {
                WorkflowId = execution.WorkflowId,
                QueryName  = queryType,
                QueryArgs  = queryArgs,
                RunId      = execution.RunId,
                Domain     = ResolveDomain(domain)
            });

            reply.ThrowOnError();

            return(reply.Result);
        }
Example #16
0
        /// <summary>
        /// Used to externally cancel an activity identified by <see cref="WorkflowExecution"/> and activity ID.
        /// </summary>
        /// <param name="execution">The workflow execution.</param>
        /// <param name="activityId">The activity ID.</param>
        /// <param name="domain">Optionally overrides the default <see cref="CadenceClient"/> domain.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="EntityNotExistsException">Thrown if the activity no longer exists.</exception>
        public async Task ActivityCancelByIdAsync(WorkflowExecution execution, string activityId, string domain = null)
        {
            await SyncContext.ClearAsync;

            Covenant.Requires <ArgumentNullException>(execution != null, nameof(execution));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(activityId), nameof(activityId));
            EnsureNotDisposed();

            var reply = (ActivityCompleteReply) await CallProxyAsync(
                new ActivityCompleteRequest()
            {
                Domain     = ResolveDomain(domain),
                WorkflowId = execution.WorkflowId,
                RunId      = execution.RunId,
                ActivityId = activityId,
                Error      = new CadenceError(new CancelledException("Cancelled"))
            });

            reply.ThrowOnError();
        }
Example #17
0
        /// <summary>
        /// Used to externally complete an activity identified by <see cref="WorkflowExecution"/> and activity ID.
        /// </summary>
        /// <param name="execution">The workflow execution.</param>
        /// <param name="activityId">The activity ID.</param>
        /// <param name="result">Passed as the activity result for activity success.</param>
        /// <param name="domain">Optionally overrides the default <see cref="CadenceClient"/> domain.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="EntityNotExistsException">Thrown if the activity no longer exists.</exception>
        public async Task ActivityCompleteByIdAsync(WorkflowExecution execution, string activityId, object result = null, string domain = null)
        {
            await SyncContext.Clear;

            Covenant.Requires <ArgumentNullException>(execution != null, nameof(execution));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(activityId), nameof(activityId));
            EnsureNotDisposed();

            var reply = (ActivityCompleteReply) await CallProxyAsync(
                new ActivityCompleteRequest()
            {
                Domain     = ResolveDomain(domain),
                WorkflowId = execution.WorkflowId,
                RunId      = execution.RunId,
                ActivityId = activityId,
                Result     = GetClient(ClientId).DataConverter.ToData(result)
            });

            reply.ThrowOnError();
        }
Example #18
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="client">The associated client.</param>
 /// <param name="execution">The workflow execution.</param>
 /// <param name="domain">Optionally specifies the target domain.  This defaults to the default client domain.</param>
 internal ExternalWorkflowFuture(CadenceClient client, WorkflowExecution execution, string domain = null)
 {
     this.client    = client;
     this.Execution = execution;
     this.domain    = client.ResolveDomain(domain);
 }
Example #19
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="client">The associated client.</param>
 /// <param name="execution">The workflow execution.</param>
 internal ExternalWorkflowFuture(CadenceClient client, WorkflowExecution execution)
 {
     this.client    = client;
     this.Execution = execution;
 }
Example #20
0
            public async Task SignalAsync(WorkflowExecution execution, string signalName, params object[] args)
            {
                var dataConverter = Activity.Client.DataConverter;

                await Activity.Client.SignalWorkflowAsync(execution, signalName, dataConverter.ToData(args));
            }
Example #21
0
 public async Task <byte[]> GetResultBytesAsync(WorkflowExecution execution)
 {
     return(await Activity.Client.GetWorkflowResultAsync(execution));
 }
Example #22
0
 public async Task GetResultAsync(WorkflowExecution execution)
 {
     await Activity.Client.GetWorkflowResultAsync(execution);
 }
Example #23
0
 public async Task CancelAsync(WorkflowExecution execution)
 {
     await Activity.Client.CancelWorkflowAsync(execution);
 }