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); }
/// <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); }
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"); } } }
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) )); }
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; } }
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; } }
public MailerService(ILoggerFactory loggerFactory, IMessageHandle messageHandle) { _logger = loggerFactory.CreateLogger <MailerService>(); _messageHandle = messageHandle; }
/// <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个字符"); }
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)); }
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)); } }