예제 #1
0
        private async Task SendResponse(FlowContext context, object message)
        {
            var reply = context.FlowState == null
                ? GetReply(context.HandlerContext)
                : context.FlowState.Metadata.Reply;

            if (reply == null)
            {
                throw new YieldPointException("No response is required");
            }

            if (message.GetType().FullName != reply.ResponseTypeName)
            {
                throw new YieldPointException($"Flow must end with a response message of type {reply.ResponseTypeName}, {message.GetType().FullName} was returned instead");
            }

            var properties = new MessageProperties
            {
                CorrelationId = reply.CorrelationId
            };

            // TODO disallow if replyto is not specified?
            if (reply.ReplyTo != null)
            {
                await publisher.PublishDirect(message, reply.ReplyTo, properties, reply.Mandatory);
            }
            else
            {
                await publisher.Publish(message, properties, reply.Mandatory);
            }

            await context.Delete();
        }
예제 #2
0
        private async Task SendRequest(FlowContext context, object message, ResponseHandlerInfo responseHandlerInfo,
                                       string convergeMethodName = null, bool convergeMethodTaskSync = false)
        {
            if (context.FlowState == null)
            {
                await CreateNewFlowState(context);

                Debug.Assert(context.FlowState != null, "context.FlowState != null");
            }

            var continuationID = Guid.NewGuid();

            context.FlowState.Continuations.Add(continuationID,
                                                new ContinuationMetadata
            {
                MethodName         = responseHandlerInfo.MethodName,
                ConvergeMethodName = convergeMethodName,
                ConvergeMethodSync = convergeMethodTaskSync
            });

            var properties = new MessageProperties
            {
                CorrelationId = continuationID.ToString(),
                ReplyTo       = responseHandlerInfo.ReplyToQueue
            };

            await context.Store(responseHandlerInfo.IsDurableQueue);

            await publisher.Publish(message, properties, true);
        }
예제 #3
0
        private static async Task EndFlow(FlowContext context)
        {
            await context.Delete();

            if (context.FlowState?.Metadata.Reply != null)
            {
                throw new YieldPointException($"Flow must end with a response message of type {context.FlowState.Metadata.Reply.ResponseTypeName}");
            }
        }
        private static async Task <FlowContext> GetFlowContext(IMessageContext context)
        {
            if (context.Items.ContainsKey(ContextItems.FlowContext))
            {
                return((FlowContext)context.Items[ContextItems.FlowContext]);
            }

            if (context.Properties.CorrelationId == null)
            {
                return(null);
            }

            Guid continuationID;

            if (!Guid.TryParse(context.Properties.CorrelationId, out continuationID))
            {
                return(null);
            }

            var flowStore = context.DependencyResolver.Resolve <IFlowStore>();

            var flowID = await flowStore.FindFlowID(continuationID);

            if (!flowID.HasValue)
            {
                return(null);
            }

            var flowStateLock = await flowStore.LockFlowState(flowID.Value);

            var flowState = await flowStateLock.GetFlowState();

            if (flowState == null)
            {
                return(null);
            }

            ContinuationMetadata continuation;

            var flowContext = new FlowContext
            {
                MessageContext = context,

                FlowStateLock = flowStateLock,
                FlowState     = flowState,

                ContinuationID       = continuationID,
                ContinuationMetadata = flowState.Continuations.TryGetValue(continuationID, out continuation) ? continuation : null
            };

            // IDisposable items in the IMessageContext are automatically disposed
            context.Items.Add(ContextItems.FlowContext, flowContext);
            return(flowContext);
        }
예제 #5
0
        /// <inheritdoc />
        public async Task Execute(IFlowHandlerContext context, IYieldPoint yieldPoint)
        {
            if (!(yieldPoint is DelegateYieldPoint executableYieldPoint))
            {
                throw new YieldPointException($"Yield point is required in controller {context.Controller.GetType().Name} for method {context.Method.Name}");
            }

            FlowContext flowContext        = null;
            var         disposeFlowContext = false;

            try
            {
                var messageContext = context.ControllerMessageContext;
                if (messageContext == null || !messageContext.Get(ContextItems.FlowContext, out flowContext))
                {
                    flowContext = new FlowContext
                    {
                        HandlerContext = context
                    };

                    // If we ended up here it is because of a Start. No point in storing the new FlowContext
                    // in the messageContext as the yield point is the last to execute.
                    disposeFlowContext = true;
                }

                try
                {
                    await executableYieldPoint.Execute(flowContext);
                }
                catch (YieldPointException e)
                {
                    // Useful for debugging
                    e.Data["Tapeti.Controller.Name"]   = context.Controller.GetType().FullName;
                    e.Data["Tapeti.Controller.Method"] = context.Method.Name;
                    throw;
                }

                flowContext.EnsureStoreOrDeleteIsCalled();
            }
            finally
            {
                if (disposeFlowContext)
                {
                    flowContext.Dispose();
                }
            }
        }
예제 #6
0
        public async Task Execute(IMessageContext context, IYieldPoint yieldPoint)
        {
            var executableYieldPoint = yieldPoint as DelegateYieldPoint;

            if (executableYieldPoint == null)
            {
                throw new YieldPointException($"Yield point is required in controller {context.Controller.GetType().Name} for method {context.Binding.Method.Name}");
            }

            FlowContext flowContext;
            object      flowContextItem;

            if (!context.Items.TryGetValue(ContextItems.FlowContext, out flowContextItem))
            {
                flowContext = new FlowContext
                {
                    MessageContext = context
                };

                context.Items.Add(ContextItems.FlowContext, flowContext);
            }
            else
            {
                flowContext = (FlowContext)flowContextItem;
            }


            try
            {
                if (executableYieldPoint != null)
                {
                    await executableYieldPoint.Execute(flowContext);
                }
            }
            catch (YieldPointException e)
            {
                // Useful for debugging
                e.Data["Tapeti.Controller.Name"]   = context.Controller.GetType().FullName;
                e.Data["Tapeti.Controller.Method"] = context.Binding.Method.Name;
                throw;
            }

            flowContext.EnsureStoreOrDeleteIsCalled();
        }
예제 #7
0
        private static async Task CreateNewFlowState(FlowContext flowContext)
        {
            var flowStore = flowContext.HandlerContext.Config.DependencyResolver.Resolve <IFlowStore>();

            var flowID = Guid.NewGuid();

            flowContext.FlowStateLock = await flowStore.LockFlowState(flowID);

            if (flowContext.FlowStateLock == null)
            {
                throw new InvalidOperationException("Unable to lock a new flow");
            }

            flowContext.FlowState = new FlowState
            {
                Metadata = new FlowMetadata
                {
                    Reply = GetReply(flowContext.HandlerContext)
                }
            };
        }
예제 #8
0
        private async Task SendResponse(FlowContext context, object message)
        {
            var reply = context.FlowState == null
                ? GetReply(context.MessageContext)
                : context.FlowState.Metadata.Reply;

            if (reply == null)
            {
                throw new YieldPointException("No response is required");
            }

            if (message.GetType().FullName != reply.ResponseTypeName)
            {
                throw new YieldPointException($"Flow must end with a response message of type {reply.ResponseTypeName}, {message.GetType().FullName} was returned instead");
            }

            var properties = new BasicProperties();

            // Only set the property if it's not null, otherwise a string reference exception can occur:
            // http://rabbitmq.1065348.n5.nabble.com/SocketException-when-invoking-model-BasicPublish-td36330.html
            if (reply.CorrelationId != null)
            {
                properties.CorrelationId = reply.CorrelationId;
            }

            // TODO disallow if replyto is not specified?
            if (reply.ReplyTo != null)
            {
                await publisher.PublishDirect(message, reply.ReplyTo, properties);
            }
            else
            {
                await publisher.Publish(message, properties);
            }

            await context.Delete();
        }
예제 #9
0
 public Task Execute(FlowContext context)
 {
     return(onExecute(context));
 }
예제 #10
0
 public async Task Execute(FlowContext context)
 {
     await onExecute(context);
 }