/// <inheritdoc/> protected override async Task ProcessAsync(CancellationToken cancellationToken) { if (!this.Activity.Metadata.TryGetValue(V1WorkflowActivityMetadata.Subflow, out var workflowInstanceId)) { workflowInstanceId = await this.Context.Workflow.StartSubflowAsync($"{this.Subflow.WorkflowId}:{this.Subflow.Version}", this.Activity.Input, cancellationToken); this.Activity.Metadata.Add(V1WorkflowActivityMetadata.Subflow, workflowInstanceId); await this.Context.Workflow.SetActivityMetadataAsync(this.Activity, cancellationToken); } switch (this.Subflow.InvocationMode) { case InvocationMode.Asynchronous: await this.OnNextAsync(new V1WorkflowActivityCompletedIntegrationEvent(this.Activity.Id, this.Activity.Input), this.CancellationTokenSource.Token); await this.OnCompletedAsync(this.CancellationTokenSource.Token); break; case InvocationMode.Synchronous: var eventDefinition = new EventDefinition() { Kind = EventKind.Consumed, Name = "onSubflowExecuted", Source = CloudEvents.Source.ToString(), Type = CloudEvents.TypeOf(typeof(V1WorkflowInstanceExecutedIntegrationEvent), typeof(V1WorkflowInstance)), Correlations = new() { new() { ContextAttributeName = nameof(CloudEvent.Subject).ToLower(), ContextAttributeValue = workflowInstanceId } } }; var e = await this.Context.Workflow.ConsumeOrBeginCorrelateEventAsync(eventDefinition, cancellationToken); if (e != null) { await this.OnEventAsync(e); return; } this.Subscription = this.IntegrationEventBus.InboundStream .Where(e => e.Subject == workflowInstanceId && e.Source?.ToString() == eventDefinition.Source && e.Type == eventDefinition.Type) .SubscribeAsync(this.OnEventAsync); if (this.Options.Correlation.Timeout.HasValue) { this.IdleTimer = new Timer(async state => await this.OnIdleTimerExpiredAsync(state, cancellationToken), null, this.Options.Correlation.Timeout.Value, this.Options.Correlation.Timeout.Value); } break; default: throw new NotSupportedException($"The specified {nameof(InvocationMode)} '{this.Subflow.InvocationMode}' is not supported"); } }
/// <summary> /// Publishes a <see cref="CloudEvent"/> for the specified <see cref="IDomainEvent"/> /// </summary> /// <param name="e">The <see cref="IDomainEvent"/> to publish a new <see cref="CloudEvent"/> for</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/></param> /// <returns>A new awaitable <see cref="Task"/></returns> protected virtual async Task PublishIntegrationEventAsync <TEvent>(TEvent e, CancellationToken cancellationToken) where TEvent : class, IDomainEvent { if (!e.GetType().TryGetCustomAttribute(out DataTransferObjectTypeAttribute dataTransferObjectTypeAttribute)) { return; } var integrationEvent = (V1IntegrationEvent)this.Mapper.Map(e, e.GetType(), dataTransferObjectTypeAttribute.Type); var aggregateType = e.GetType().GetGenericType(typeof(DomainEvent <,>)).GetGenericArguments()[0]; var cloudEvent = new CloudEvent() { Id = Guid.NewGuid().ToString(), Source = CloudEvents.Source, Type = CloudEvents.TypeOf(typeof(TEvent), aggregateType), Time = e.CreatedAt, Subject = e.AggregateId.ToString(), DataSchema = CloudEvents.SchemaOf(typeof(TEvent), aggregateType), DataContentType = MediaTypeNames.Application.Json, Data = integrationEvent }; await this.IntegrationEventBus.PublishAsync(cloudEvent, cancellationToken); }