public async void Subscribe(EventDescriptor eventDesc, EventSubscriberDescriptor subscriber) { var fabricConnectorToSubscriber = _fabricConnectorSelector.Select(subscriber.ServiceId); var fabricConnectorToPublisher = _fabricConnectorSelector.Select(eventDesc.ServiceId); if (fabricConnectorToSubscriber.GetType() != fabricConnectorToPublisher.GetType()) throw new NotSupportedException("Multi-type fabric is not supported for events, because it's an infrastructure configuration concern."); await fabricConnectorToSubscriber.SubscribeForEventAsync(eventDesc, subscriber, fabricConnectorToPublisher); await fabricConnectorToPublisher.OnEventSubscriberAddedAsync(eventDesc, subscriber, fabricConnectorToSubscriber); }
public async Task CommitAsync( ITransitionCarrier transitionCarrier, ScheduledActions actions, CancellationToken ct) { #warning This need deep thinking on how to achieve transictionality if (actions.SaveStateIntent != null) { #warning Make sure that saving service and routine state is transactional - you don't want to re-run routine on failure after service state was saved only. var intent = actions.SaveStateIntent; await transitionCarrier.SaveStateAsync(intent, ct); } if (actions.ExecuteRoutineIntents?.Count > 0) { foreach (var intent in actions.ExecuteRoutineIntents) { var connector = _fabricConnectorSelector.Select(intent.ServiceId); #warning TODO: try to pre-generate routine ID - needed for transactionality. #warning TODO: check if target fabric can route back the continuation. If not, come up with another strategy, e.g. polling, or gateway? var info = await connector.ScheduleRoutineAsync(intent, ct); #warning TODO: check if routine is already done - it's possible on retry to run the transition, or under some special circumstances. #warning TODO: save scheduled routine info into current routine's state - needed for dynamic subscription. } } if (actions.ResumeRoutineIntent != null) { #warning need ability to overwrite existing message instead of creating a new one (if supported) var intent = actions.ResumeRoutineIntent; var connector = _fabricConnectorSelector.Select(intent.Continuation.ServiceId); var info = await connector.ScheduleContinuationAsync(intent, ct); } if (actions.ContinuationIntents?.Count > 0) { foreach (var intent in actions.ContinuationIntents) { var connector = _fabricConnectorSelector.Select(intent.Continuation.ServiceId); var info = await connector.ScheduleContinuationAsync(intent, ct); } } }
/// <remarks> /// Fire and forget mode (async void). /// </remarks> public async void ExecuteAndAwaitInBackground(ExecuteRoutineIntent intent, Task proxyTask) { #warning Add infrastructure exception handling try { #warning need to associate a routine with a cancellaion token, and abandon polling when canceled var ct = CancellationToken.None; var fabricConnector = _fabricConnectorSelector.Select(intent.ServiceId); var routineInfo = await fabricConnector.ScheduleRoutineAsync(intent, ct); for (var i = 0; ; i++) { #warning Ideally need to handle 'fire an forget' cases - the continuation is never set? //if (!proxyTask.continuation == null after 1 min?) // return; routineInfo = await fabricConnector.PollRoutineResultAsync(routineInfo, ct); if (routineInfo.Result != null) { break; } TimeSpan delayInterval; if (routineInfo is IRoutinePollInterval routinePollInterval) { delayInterval = routinePollInterval.Suggest(i); } else { delayInterval = TimeSpan.FromSeconds(0.5); } await Task.Delay(delayInterval); } if (!proxyTask.TrySetResult(routineInfo.Result)) { throw new InvalidOperationException("Critical error - cannot set result to the proxy task."); } } catch (Exception ex) { //Console.WriteLine(ex.ToString()); throw; } }
public async Task CommitAsync( ScheduledActions actions, // Carrier is NULL when call is made outside of a transition scope, e.g. from entry point of a console app. ITransitionCarrier transitionCarrier, TransitionCommitOptions options, CancellationToken ct) { #warning This need deep thinking on how to achieve consistency if (actions.SaveStateIntent != null) { #warning Make sure that saving service and routine state is transactional - you don't want to re-run routine on failure after service state was saved only. var intent = actions.SaveStateIntent; await((ITransitionStateSaver)transitionCarrier).SaveStateAsync(intent, ct); } if (actions.ExecuteRoutineIntents?.Count > 0) { foreach (var intent in actions.ExecuteRoutineIntents) { var connector = _fabricConnectorSelector.Select(intent.ServiceId); #warning TODO: try to pre-generate routine ID - needed for transactionality. #warning TODO: check if target fabric can route back the continuation. If not, come up with another strategy, e.g. polling, or gateway? var info = await connector.ScheduleRoutineAsync(intent, ct); #warning TODO: check if routine is already done - it's possible on retry to run the transition, or under some special circumstances. #warning TODO: save scheduled routine info into current routine's state - needed for dynamic subscription. if (options.NotifyOnRoutineCompletion) { ((IInternalRoutineCompletionNotifier)_routineCompletionNotifier).RegisterComittedRoutine(intent.Id, connector, info); } } } if (actions.ResumeRoutineIntent != null) { #warning need ability to overwrite existing message instead of creating a new one (if supported) var intent = actions.ResumeRoutineIntent; var connector = _fabricConnectorSelector.Select(intent.Continuation.ServiceId); var info = await connector.ScheduleContinuationAsync(intent, ct); } if (actions.ContinuationIntents?.Count > 0) { foreach (var intent in actions.ContinuationIntents) { var connector = _fabricConnectorSelector.Select(intent.Continuation.ServiceId); var info = await connector.ScheduleContinuationAsync(intent, ct); } } if (actions.RaiseEventIntents?.Count > 0) { foreach (var intent in actions.RaiseEventIntents) { if (intent.ServiceId == null) { throw new NotSupportedException(); } var connector = _fabricConnectorSelector.Select(intent.ServiceId); await connector.PublishEventAsync(intent, ct); } } if (actions.RegisterTriggerIntents?.Count > 0) { var connector = ((ICurrentConnectorProvider)transitionCarrier).Connector; foreach (var intent in actions.RegisterTriggerIntents) { await connector.RegisterTriggerAsync(intent, ct); } } if (actions.ActivateTriggerIntents?.Count > 0) { var connector = ((ICurrentConnectorProvider)transitionCarrier).Connector; foreach (var intent in actions.ActivateTriggerIntents) { await connector.ActivateTriggerAsync(intent, ct); } } if (actions.SubscribeToTriggerIntents?.Count > 0) { var connector = ((ICurrentConnectorProvider)transitionCarrier).Connector; foreach (var intent in actions.SubscribeToTriggerIntents) { await connector.SubscribeToTriggerAsync(intent, ct); } } }