Example #1
0
        public async Task <IMessageHandle> UpdateMessageAsync(IMessageHandle handle, IMessage message)
        {
            var actualMessage = (SlackMessage)message;
            var dao           = await _slackMessageRepository.Find(handle.Id);

            _log.LogInformation($"Sending message update for [{dao.Timestamp}/${dao.ChannelId}]");
            var response = await UpdateWithBlocksAsync(
                dao.Timestamp,
                dao.ChannelId,
                actualMessage.Message,
                blocks : actualMessage.Blocks, as_user : true
                );

            if (!response.ok || !string.IsNullOrEmpty(response.error))
            {
                _log.LogError("Failed to send message update via Slack [{error}]", response.error);
                throw new InvalidOperationException($"Failed to send message via Slack [{response.error}]");
            }

            _log.LogTrace(
                $"Updated message via slack [{response.ts}/${response.channel}]"
                );
            dao.ChannelId       = response.channel;
            dao.Timestamp       = response.ts;
            dao.UpdatedDateTime = DateTimeOffset.Now;

            await _slackMessageRepository.Save();

            return(handle);
        }
Example #2
0
 /// <summary>
 /// 初始化agent
 /// </summary>
 /// <param name="factory"></param>
 /// <param name="master">指定master server,若为空则忽略</param>
 /// <param name="name">agent节点名</param>
 /// <param name="description">agent节点描述</param>
 /// <param name="handle"></param>
 public DefaultAgent(ILoggerFactory factory
     , string master
     , string name
     , string description
     , IMessageHandle handle)
     : this(factory.Create(typeof(DefaultAgent))
     , master, name, description, handle)
 {
     this._log = factory.Create(this.GetType());
 }
        public void AddHandle(IMessageHandle handle)
        {
            if (_handles.ContainsKey(handle.Id))
            {
                throw new Exception(string.Format("Handle for id: {0} already defined.", handle.Id));
            }

            handle.SetMessageSerializer(this);
            _handles.Add(handle.Id, handle);
        }
Example #4
0
        public void Init()
        {
            operationMap = new Dictionary <OperationType, Dictionary <OperationCode, List <Action <string, OperationType, OperationCode, ByteArray> > > >();
            Assembly assembly = Assembly.GetExecutingAssembly();

            Type[] ts = assembly.GetTypes();
            foreach (Type t in ts)
            {
                if (typeof(IMessageHandle).IsAssignableFrom(t) && !t.IsInterface)
                {
                    Console.WriteLine("create IMessageHandle instance: " + t);
                    IMessageHandle handle = Activator.CreateInstance(t) as IMessageHandle;
                    handle?.Init();
                    Console.WriteLine(handle + " Init");
                }
            }
        }
Example #5
0
        public async Task <IMessageHandle> UpdateDeploymentUpdateNotification(
            IMessageHandle handle,
            DeploymentUpdate deploymentUpdate,
            DeploymentUpdateStatus status
            )
        {
            if (handle == null)
            {
                throw new ArgumentNullException(nameof(handle));
            }
            if (deploymentUpdate == null)
            {
                throw new ArgumentNullException(nameof(deploymentUpdate));
            }

            return(await UpdateMessageAsync(
                       handle as SingleMessageHandle,
                       BuildDeploymentUpdateMessage(deploymentUpdate, status)
                       ));
        }
Example #6
0
        public async Task <InvokeRoutineResult> RunAsync(MethodInvocationData data, ICommunicatorMessage message)
        {
            var serviceReference = _serviceResolver.Resolve(data.Service);
            var methodReference  = _methodResolver.Resolve(serviceReference.Definition, data.Method);

            var behaviorSettings = _communicationSettingsProvider.GetMethodSettings(methodReference.Definition);

            //-------------------------------------------------------------------------------
            // MESSGE DE-DUPLICATION
            //-------------------------------------------------------------------------------

            bool needsDeduplication = behaviorSettings.Deduplicate;

            if (methodReference.Definition.IsQuery)
            {
                // NOTE: you can run queries using message passing (non-volatile),
                // or the volatile method uses a callback instead of re-trying.
                if (message.CommunicatorTraits.HasFlag(CommunicationTraits.Volatile) && data.Continuation == null)
                {
                    needsDeduplication = false;
                }
            }
            if (needsDeduplication &&
                !message.CommunicatorTraits.HasFlag(CommunicationTraits.MessageDeduplication) &&
                (message.IsRetry != false || string.IsNullOrEmpty(message.RequestId)))
            {
                // TODO: if has message de-dup'er, check if a dedup
                // return new InvokeRoutineResult { Outcome = InvocationOutcome.Deduplicated };
            }

            //-------------------------------------------------------------------------------
            // UNIT OF WORK
            //-------------------------------------------------------------------------------

            // TODO: Unit of Work - check if there is cached/stored data
            if (message.IsRetry != false)
            {
                // TODO: If has entities in transitions and they have been already committed,
                // skip method transition and re-try sending commands and events.
            }

            //-------------------------------------------------------------------------------
            // DELEGATION TO RESILIENT COMMUNICATOR
            //-------------------------------------------------------------------------------

            IMessageHandle messageHandle = null;

            if (behaviorSettings.Persistent && message.CommunicatorTraits.HasFlag(CommunicationTraits.Volatile))
            {
                // TODO: check if can poll for result! (think about continuation and sync invocation)

                var preferredCommunicator = _communicatorProvider.GetCommunicator(data.Service, data.Method);
                if (message.CommunicatorType != preferredCommunicator.Type &&
                    !preferredCommunicator.Traits.HasFlag(CommunicationTraits.Volatile))
                {
                    var resultValueType = methodReference.Definition.MethodInfo.ReturnType;
                    if (resultValueType != typeof(void))
                    {
                        resultValueType = TaskAccessor.GetTaskResultType(resultValueType);
                        if (resultValueType == TaskAccessor.VoidTaskResultType)
                        {
                            resultValueType = typeof(void);
                        }
                    }

                    var preferences = new InvocationPreferences
                    {
                        LockMessage = behaviorSettings.RunInPlace &&
                                      preferredCommunicator.Traits.HasFlag(CommunicationTraits.MessageLockOnPublish),
                        ResultValueType = resultValueType
                    };

                    var invocationResult = await preferredCommunicator.InvokeAsync(data, preferences);

                    if (invocationResult.Outcome == InvocationOutcome.Complete && !string.IsNullOrEmpty(data.IntentId))
                    {
                        _routineCompletionSink.OnRoutineCompleted(data.Service, data.Method, data.IntentId, invocationResult.Result);
                    }

                    if (invocationResult.Outcome == InvocationOutcome.Scheduled && invocationResult.MessageHandle != null)
                    {
                        // NOTE: will run synchronously below
                        messageHandle = invocationResult.MessageHandle;
                    }
                    else
                    {
                        return(invocationResult);
                    }
                }
            }

            //-------------------------------------------------------------------------------
            // RUN METHOD TRANSITION
            //-------------------------------------------------------------------------------

            try
            {
                var adapter = new TransitionCarrier(data, _valueContainerCopier, message);
                var transitionDescriptor = new TransitionDescriptor {
                    Type = TransitionType.InvokeRoutine
                };
                var result = await RunRoutineAsync(adapter, transitionDescriptor, default);

                if (result.Outcome == InvocationOutcome.Complete && !string.IsNullOrEmpty(data.IntentId))
                {
                    _routineCompletionSink.OnRoutineCompleted(data.Service, data.Method, data.IntentId, result.Result);
                }
                if (messageHandle != null)
                {
                    await messageHandle.Complete();
                }
                return(result);
            }
            catch
            {
                messageHandle?.ReleaseLock();
                throw;
            }
        }
Example #7
0
        public async Task <ContinueRoutineResult> ContinueAsync(MethodContinuationData data, ICommunicatorMessage message)
        {
            var serviceReference = _serviceResolver.Resolve(data.Service);
            var methodReference  = _methodResolver.Resolve(serviceReference.Definition, data.Method);

            var behaviorSettings = _communicationSettingsProvider.GetMethodSettings(methodReference.Definition);

            //-------------------------------------------------------------------------------
            // MESSGE DE-DUPLICATION
            //-------------------------------------------------------------------------------

            if (behaviorSettings.Deduplicate &&
                !message.CommunicatorTraits.HasFlag(CommunicationTraits.MessageDeduplication) &&
                (message.IsRetry != false || string.IsNullOrEmpty(message.RequestId)))
            {
                // TODO: if has message de-dup'er, check if a dedup
                // return new InvokeRoutineResult { Outcome = InvocationOutcome.Deduplicated };
            }

            //-------------------------------------------------------------------------------
            // UNIT OF WORK
            //-------------------------------------------------------------------------------

            // TODO: Unit of Work - check if there is cached/stored data
            if (message.IsRetry != false)
            {
                // TODO: If has entities in transitions and they have been already committed,
                // skip method transition and re-try sending commands and events.
            }

            //-------------------------------------------------------------------------------
            // DELEGATION TO RESILIENT COMMUNICATOR
            //-------------------------------------------------------------------------------

            IMessageHandle messageHandle = null;

            if (behaviorSettings.Persistent && message.CommunicatorTraits.HasFlag(CommunicationTraits.Volatile))
            {
                // TODO: check if can poll for result! (think about continuation and sync invocation)

                var preferredCommunicator = _communicatorProvider.GetCommunicator(data.Service, data.Method);
                if (message.CommunicatorType != preferredCommunicator.Type &&
                    !preferredCommunicator.Traits.HasFlag(CommunicationTraits.Volatile))
                {
                    var preferences = new InvocationPreferences
                    {
                        LockMessage = behaviorSettings.RunInPlace &&
                                      preferredCommunicator.Traits.HasFlag(CommunicationTraits.MessageLockOnPublish)
                    };

                    var invocationResult = await preferredCommunicator.ContinueAsync(data, preferences);

                    if (!preferences.LockMessage || invocationResult.MessageHandle == null)
                    {
                        return(new ContinueRoutineResult {
                        });
                    }

                    // NOTE: will run synchronously below
                    messageHandle = invocationResult.MessageHandle;
                }
            }

            //-------------------------------------------------------------------------------
            // RUN METHOD TRANSITION
            //-------------------------------------------------------------------------------

            // A communication method may not support a scheduled message delivery.
            if (data.ContinueAt.HasValue && data.ContinueAt.Value > DateTimeOffset.Now)
            {
                var delay = data.ContinueAt.Value - DateTimeOffset.Now;
                if (delay > TimeSpan.Zero)
                {
                    await Task.Delay(delay);
                }
            }

            try
            {
@TryRun:
                var adapter = new TransitionCarrier(data, message);

                MethodExecutionState methodState = DecodeContinuationData(data.State);
                if (methodState == null)
                {
                    var stateStorage = _methodStateStorageProvider.GetStorage(data.Service, data.Method, returnNullIfNotFound: true);
                    if (stateStorage == null)
                    {
                        throw new InvalidOperationException($"Cannot resume method '{data.Service}'.{data.Method} due to absence of a persistence mechanism.");
                    }

                    // TODO: a method can be already completed or transitioned (duplicate messages?) - discard transition?
                    methodState = await stateStorage.ReadStateAsync(data.Service, data.Method, default);
                }

                adapter.SetMethodExecutionState(methodState, _valueContainerCopier);

                InvokeRoutineResult result;
                try
                {
                    var transitionDescriptor = new TransitionDescriptor {
                        Type = TransitionType.ContinueRoutine
                    };
                    result = await RunRoutineAsync(adapter, transitionDescriptor, default);
                }
                catch (ConcurrentTransitionException)
                {
                    goto TryRun;
                }

                if (result.Outcome == InvocationOutcome.Complete && !string.IsNullOrEmpty(data.Method.IntentId))
                {
                    _routineCompletionSink.OnRoutineCompleted(data.Service, data.Method, data.Method.IntentId, result.Result);
                }

                if (messageHandle != null)
                {
                    await messageHandle.Complete();
                }

                return(new ContinueRoutineResult
                {
                });
            }
            catch
            {
                messageHandle?.ReleaseLock();
                throw;
            }
        }
Example #8
0
 public MailerService(ILoggerFactory loggerFactory, IMessageHandle messageHandle)
 {
     _logger        = loggerFactory.CreateLogger <MailerService>();
     _messageHandle = messageHandle;
 }
Example #9
0
        /// <summary>
        /// 初始化agent
        /// </summary>
        /// <param name="log"></param>
        /// <param name="master">指定master server,若为空则忽略</param>
        /// <param name="name">agent节点名</param>
        /// <param name="description">agent节点描述</param>
        /// <param name="handle"></param>
        public DefaultAgent(ILog log
            , string master
            , string name
            , string description
            , IMessageHandle handle)
        {
            if (string.IsNullOrEmpty(name)
                || handle == null
                || log == null)
                throw new InvalidOperationException("name|handle|log均不能为空");

            this._name = name;
            this._description = description;
            this._master = master;
            this._handle = handle;
            this._log = log;

            if (!string.IsNullOrEmpty(this._description)
                && this._description.Length > 100)
                throw new InvalidOperationException("description不能超过100个字符");
        }
Example #10
0
            public BuilderCore <TKey, TProtocol> RegistMessageHandle <TMessage>(TKey key, IMessageHandle <TKey, TProtocol, TMessage> messageHandle)
            {
                if (messageHandle is null)
                {
                    throw new ArgumentNullException(nameof(messageHandle));
                }

                _messageMapping.Add(key, typeof(TMessage));
                _messageHandle.Add(key, messageHandle);

                return(this);
            }
 public static IDisposable Subscribe <T>(this IObservable <T> observable, IMessageHandle <T> endPoint)
 {
     return(observable.Subscribe(endPoint.OnMessage, endPoint.OnError, endPoint.OnCompleted));
 }
 public static IObservable <T> PrintHandler <T>(this IObservable <T> observable, IMessageHandle <T> messageHandle)
 {
     return(observable.Do(messageHandle.OnMessage, messageHandle.OnError, messageHandle.OnCompleted));
 }
Example #13
0
        public async Task <InvokeRoutineResult> InvokeAsync(ExecuteRoutineIntent intent)
        {
            var serviceRef = _serviceResolver.Resolve(intent.Service);
            var methodRef  = _methodResolver.Resolve(serviceRef.Definition, intent.Method);

            var behaviorSettings = _communicationSettingsProvider.GetMethodSettings(methodRef.Definition);

            ICommunicator communicator = _communicatorProvider.GetCommunicator(serviceRef.Id, methodRef.Id);

            bool preferToRunInPlace = behaviorSettings.RunInPlace && serviceRef.Definition.Type != ServiceType.External;
            bool runInPlace         = preferToRunInPlace && (!behaviorSettings.Persistent ||
                                                             communicator.Traits.HasFlag(CommunicationTraits.MessageLockOnPublish));

            var invocationData = InvocationDataUtils.CreateMethodInvocationData(intent,
                                                                                _transitionScope.IsActive ? _transitionScope.CurrentMonitor.Context : null);

            var resultValueType = methodRef.Definition.MethodInfo.ReturnType;

            if (resultValueType != typeof(void))
            {
                resultValueType = TaskAccessor.GetTaskResultType(resultValueType);
                if (resultValueType == TaskAccessor.VoidTaskResultType)
                {
                    resultValueType = typeof(void);
                }
            }

            if (runInPlace)
            {
                IMessageHandle messageHandle = null;
                if (behaviorSettings.Persistent)
                {
                    var preferences = new InvocationPreferences
                    {
                        LockMessage     = true,
                        ResultValueType = resultValueType
                    };

                    var invocationResult = await communicator.InvokeAsync(invocationData, preferences);

                    if (invocationResult.Outcome == InvocationOutcome.Complete)
                    {
                        return(invocationResult);
                    }
                    messageHandle = invocationResult.MessageHandle;
                }

                try
                {
                    var result = await _localMethodRunner.RunAsync(
                        invocationData,
                        RuntimeCommunicatorMessage.Instance);

                    if (messageHandle != null)
                    {
                        await messageHandle.Complete();
                    }

                    return(result);
                }
                catch (Exception ex) // TODO: infra exceptions? should not be there, right?
                {
                    if (messageHandle != null)
                    {
                        messageHandle.ReleaseLock();
                    }

                    return(new InvokeRoutineResult
                    {
                        Outcome = InvocationOutcome.Scheduled,
                        MessageHandle = messageHandle
                    });
                }
            }
            else
            {
                var preferences = new InvocationPreferences
                {
                    // TODO: check this option
                    //LockMessage = behaviorSettings.Resilient && communicator.Traits.HasFlag(CommunicationTraits.MessageLockOnPublish),

                    Synchronous     = communicator.Traits.HasFlag(CommunicationTraits.SyncReplies),
                    ResultValueType = resultValueType
                };

                return(await communicator.InvokeAsync(invocationData, preferences));
            }
        }