예제 #1
0
        /// <inheritdoc/>
        public override async Task Connect(
            IAsyncStreamReader <FilterClientToRuntimeMessage> runtimeStream,
            IServerStreamWriter <FilterRuntimeToClientMessage> clientStream,
            ServerCallContext context)
        {
            _logger.Debug("Connecting Unpartitioned Filter");
            using var cts = CancellationTokenSource.CreateLinkedTokenSource(_hostApplicationLifetime.ApplicationStopping, context.CancellationToken);
            var cancellationToken = cts.Token;
            var dispatcher        = _reverseCallDispatchers.GetFor <FilterClientToRuntimeMessage, FilterRuntimeToClientMessage, FilterRegistrationRequest, FilterRegistrationResponse, FilterEventRequest, FilterResponse>(
                runtimeStream,
                clientStream,
                context,
                _ => _.RegistrationRequest,
                (serverMessage, registrationResponse) => serverMessage.RegistrationResponse = registrationResponse,
                (serverMessage, request) => serverMessage.FilterRequest = request,
                _ => _.FilterResult,
                _ => _.CallContext,
                (request, context) => request.CallContext = context,
                _ => _.CallContext,
                (message, ping) => message.Ping = ping,
                message => message.Pong);

            if (await RejectIfNotReceivedArguments(dispatcher, cancellationToken).ConfigureAwait(false))
            {
                return;
            }

            var arguments        = dispatcher.Arguments;
            var executionContext = arguments.CallContext.ExecutionContext.ToExecutionContext();

            _logger.Trace("Setting execution context{NewLine}{ExecutionContext}", System.Environment.NewLine, executionContext);
            _executionContextManager.CurrentFor(arguments.CallContext.ExecutionContext);

            var filterId       = arguments.FilterId.To <StreamId>();
            var scopeId        = arguments.ScopeId.To <ScopeId>();
            var sourceStreamId = StreamId.EventLog;

            if (await RejectIfInvalidFilterId(dispatcher, filterId, cancellationToken).ConfigureAwait(false))
            {
                return;
            }

            var filterDefinition = new FilterDefinition(sourceStreamId, filterId, partitioned: false);

            await RegisterFilter(
                dispatcher,
                scopeId,
                filterDefinition,
                () => new FilterProcessor(
                    scopeId,
                    filterDefinition,
                    dispatcher,
                    _getEventsToStreamsWriter(),
                    _loggerManager.CreateLogger <FilterProcessor>()),
                cancellationToken).ConfigureAwait(false);
        }
        /// <inheritdoc/>
        public ICommandContext EstablishForCommand(CommandRequest command)
        {
            _logger.Debug("Establishing command context for command '{CommandType}' with correlation '{CorrelationId}'", command.Type, command.CorrelationId);
            if (!IsInContext(command))
            {
                _executionContextManager.CurrentFor(_executionContextManager.Current.Tenant, command.CorrelationId);
                _currentContext.Value = _factory.Build(command);
            }
            else
            {
                _executionContextManager.CurrentFor(_currentContext.Value.ExecutionContext);
            }

            return(_currentContext.Value);
        }
예제 #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="queryRequest"></param>
        /// <returns></returns>
        public async Task <QueryResult> Execute(QueryRequest queryRequest)
        {
            QueryResult result = null;

            try
            {
                _executionContextManager.CurrentFor(TenantId.Development, Dolittle.Execution.CorrelationId.New(), ClaimsPrincipal.Current.ToClaims());

                var queryType = _typeFinder.GetQueryTypeByName(queryRequest.GeneratedFrom);
                var query     = _container.Get(queryType) as IQuery;

                PopulateProperties(queryRequest, queryType, query);

                _logger.Trace($"Executing runtime query coordinator");
                result = await _queryCoordinator.Execute(query, new PagingInfo());

                if (result.Success)
                {
                    AddClientTypeInformation(result);
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"Error executing query : '{queryRequest.NameOfQuery}'");
                result = new QueryResult
                {
                    Exception = ex,
                    QueryName = queryRequest.NameOfQuery
                };
            }

            return(result);
        }
예제 #4
0
        /// <inheritdoc />
        public void HandleWebhookPayload(ActivityPayload payload, Guid deliveryId)
        {
            IEnumerable <HandlerMethod> handlerMethods = _handlerRegistry.GetHandlersFor(payload.GetType());

            if (handlerMethods.Any())
            {
                // Figure out the execution context for this event
                var tenantId = _tenantMapper.GetTenantFor(payload.Installation.Id);

                if (tenantId == TenantId.Unknown)
                {
                    _logger.Warning($"GitHub installation '{payload.Installation.Id}' is not mapped to a tenant. The webhook will be ignored.");
                    return;
                }

                _executionContextManager.CurrentFor(tenantId, deliveryId);

                // Schedule the event for processing
                var scheduler = _schedulerFactory();
                foreach (var handler in handlerMethods)
                {
                    scheduler.QueueWebhookEventForHandling(new Webhook(handler, payload));
                }
            }
        }
        /// <inheritdoc />
        public void Process(IPod pod)
        {
            _executionContextManager.CurrentFor(pod.Metadata.Tenant);
            if (pod.IsDeleted)
            {
                _logger.Information($"Build-pod '{pod.Metadata.ToString()}' is deleted.");
                return;
            }

            if (!pod.HasBuildContainerStatuses)
            {
                _logger.Information($"Build-pod '{pod.Metadata.ToString()}' has no statuses to process.");
                return;
            }

            if (pod.HasSucceeded)
            {
                _logger.Information($"Build-pod '{pod.Metadata.ToString()}' succeeded.");
                ProcessSteps(pod);
                pod.Delete();
                return;
            }
            else if (pod.HasFailed)
            {
                _logger.Warning($"Build-pod '{pod.Metadata.ToString()}' failed.");
                pod.Delete();
                return;
            }
            _logger.Information($"Build-pod '{pod.Metadata.ToString()}' still in progress.");
            ProcessSteps(pod);
        }
예제 #6
0
        /// <summary>
        ///  Processes the <see cref="CommittedEventStreamWithContext" />
        /// </summary>
        /// <param name="committedEventStreamWithContext">The <see cref="CommittedEventStream" /> to process</param>
        protected virtual void ProcessStream(CommittedEventStreamWithContext committedEventStreamWithContext)
        {
            _executionContextManager.CurrentFor(committedEventStreamWithContext.Context);
            var committedEventStream = committedEventStreamWithContext.EventStream;

            _logger.Debug($"Processing  stream {committedEventStream.Sequence} {committedEventStream.Id} {committedEventStream.CorrelationId}");
            committedEventStream.Events.ForEach(e => Process(e.ToCommittedEventEnvelope(committedEventStream.Sequence), committedEventStreamWithContext.Context));
        }
예제 #7
0
        void ReportBuildResult(V1Pod pod, bool success)
        {
            TenantId      tenantId      = new Guid(pod.Metadata.Labels[PodLabels.Tenant]);
            ImprovementId improvementId = new Guid(pod.Metadata.Labels[PodLabels.Improvement]);

            _executionContextManager.CurrentFor(tenantId);
            var resultHandler = _improvementResultHandlerFactory();

            if (success)
            {
                resultHandler.HandleSuccess(improvementId);
            }
            else
            {
                resultHandler.HandleFailure(improvementId);
            }
        }
예제 #8
0
        /// <inheritdoc/>
        public void Perform(Action <TenantId> action)
        {
            var originalExecutionContext = _executionContextManager.Current;

            try
            {
                foreach (var tenant in _tenants.All.ToArray())
                {
                    _executionContextManager.CurrentFor(tenant);
                    action(tenant);
                }
            }
            finally
            {
                _executionContextManager.CurrentFor(originalExecutionContext);
            }
        }
예제 #9
0
        /// <summary>
        /// Middleware invocation method.
        /// </summary>
        /// <param name="context">Current <see cref="HttpContext"/>.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public Task InvokeAsync(HttpContext context)
        {
            var tenantIdHeader = _options.CurrentValue.TenantIdHeaderName;
            var tenantId       = GetTenantIdFromHeaders(context, tenantIdHeader);

            _executionContextManager.CurrentFor(tenantId, CorrelationId.New());
            return(_next.Invoke(context));
        }
        /// <inheritdoc/>
        public ExecutionContext ConfigureFor(TenantId tenantId, CorrelationId correlationId, Claims claims)
        {
            var executionEnvironment    = EnvironmentUtilities.GetExecutionEnvironment();
            var executionApplication    = DeduceApplication();
            var executionBoundedContext = DeduceBoundedContext();

            _executionContextManager.SetConstants(executionApplication, executionBoundedContext, executionEnvironment);

            return(_executionContextManager.CurrentFor(tenantId, correlationId, claims ?? Dolittle.Security.Claims.Empty));
        }
예제 #11
0
        IEnumerable <Commits> GetCommits(IEnumerable <TenantOffset> tenantOffsets)
        {
            var commits = new List <Commits>();

            Parallel.ForEach(tenantOffsets, (_) => {
                _executionContextManager.CurrentFor(_.Tenant);
                commits.Add(_unprocessedCommitFetcher.GetUnprocessedCommits(_.Offset));
            });
            return(commits);
        }
예제 #12
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BootProcedure"/> class.
        /// </summary>
        /// <param name="container">The <see cref="IContainer"/>.</param>
        /// <param name="executionContextManager">The <see cref="IExecutionContextManager"/> for managing <see cref="ExecutionContext"/>.</param>
        /// <param name="jsRuntime">The <see cref="IJSRuntime"/>.</param>
        public BootProcedure(
            IContainer container,
            IExecutionContextManager executionContextManager,
            IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;

            executionContextManager.CurrentFor(TenantId.Development);
            _configurationFor = container.Get <IConfigurationFor <Configuration> >();
        }
예제 #13
0
        /// <inheritdoc/>
        public ExecutionContext ConfigureFor(TenantId tenantId, CorrelationId correlationId, Claims claims)
        {
            var executionEnvironment    = DeduceEnvironment();
            var executionApplication    = DeduceApplication();
            var executionBoundedContext = DeduceBoundedContext();

            _executionContextManager.SetConstants(executionApplication, executionBoundedContext, executionEnvironment);

            return(_executionContextManager.CurrentFor(tenantId, correlationId, claims));
        }
        /// <summary>
        /// Set current execution context for a Protobuf <see cref="Execution.Contracts.ExecutionContext"/>.
        /// </summary>
        /// <param name="executionContextManager"><see cref="IExecutionContextManager"/> to extend.</param>
        /// <param name="executionContext"><see cref="Execution.Contracts.ExecutionContext"/> to set current.</param>
        public static void CurrentFor(this IExecutionContextManager executionContextManager, Execution.Contracts.ExecutionContext executionContext)
        {
            var microservice  = executionContext.MicroserviceId.To <Microservice>();
            var tenant        = executionContext.TenantId.To <TenantId>();
            var correlationId = executionContext.CorrelationId.To <CorrelationId>();
            var claims        = executionContext.Claims.ToClaims();

            executionContextManager.CurrentFor(
                microservice,
                tenant,
                correlationId,
                claims);
        }
예제 #15
0
        /// <inheritdoc/>
        public void Perform()
        {
            var environment = _executionContextManager.Current.Environment;

            _resourceConfiguration.ConfigureResourceTypes(
                _boundedContextConfiguration.Resources.ToDictionary(
                    kvp => kvp.Key,
                    kvp => environment == Environment.Production ? kvp.Value.Production : kvp.Value.Development));

            _executionContextManager.SetConstants(_boundedContextConfiguration.BoundedContext, Version.NotSet, environment);
            _executionContextManager.CurrentFor(_boundedContextConfiguration.BoundedContext, _executionContextManager.Current.Tenant);

            HasPerformed = true;
        }
예제 #16
0
        /// <inheritdoc/>
        public override async Task <Contracts.CommitEventsResponse> Commit(Contracts.CommitEventsRequest request, ServerCallContext context)
        {
            _executionContextManager.CurrentFor(request.CallContext.ExecutionContext);
            var response = new Contracts.CommitEventsResponse();

            try
            {
                _logger.Debug("{eventsCount} Events received for committing", request.Events.Count);
                var events            = request.Events.Select(_ => new UncommittedEvent(_.EventSourceId.To <EventSourceId>(), new Artifact(_.Artifact.Id.To <ArtifactId>(), _.Artifact.Generation), _.Public, _.Content));
                var uncommittedEvents = new UncommittedEvents(new ReadOnlyCollection <UncommittedEvent>(events.ToList()));
                var committedEvents   = await _eventStoreFactory().CommitEvents(uncommittedEvents, context.CancellationToken).ConfigureAwait(false);

                _logger.Debug("Events were successfully committed");
                response.Events.AddRange(committedEvents.ToProtobuf());
            }
            catch (Exception ex)
            {
                _logger.Warning(ex, "Error committing events");
                response.Failure = GetFailureFromException(ex);
            }

            return(response);
        }
예제 #17
0
        /// <inheritdoc/>
        public async Task <bool> ReceiveArguments(CancellationToken cancellationToken)
        {
            ThrowIfReceivingArguments();
            lock (_receiveArgumentsLock)
            {
                ThrowIfReceivingArguments();
                _receivingArguments = true;
            }

            if (await _clientStream.MoveNext(cancellationToken).ConfigureAwait(false))
            {
                var arguments = _getConnectArguments(_clientStream.Current);
                if (arguments != null)
                {
                    var callContext = _getArgumentsContext(arguments);
                    if (callContext?.PingInterval == null)
                    {
                        _logger.Warning("Received arguments, but ping interval was not set");
                        return(false);
                    }

                    var interval = callContext.PingInterval.ToTimeSpan();
                    if (interval.TotalMilliseconds <= 0)
                    {
                        _logger.Warning("Received arguments, but ping interval is less than or equal to zero milliseconds");
                        return(false);
                    }

                    _pingInterval = callContext.PingInterval.ToTimeSpan();

                    if (callContext?.ExecutionContext != null)
                    {
                        _executionContextManager.CurrentFor(callContext.ExecutionContext.ToExecutionContext());
                        Arguments = arguments;
                        return(true);
                    }
                    else
                    {
                        _logger.Warning("Received arguments, but call execution context was not set.");
                    }
                }
                else
                {
                    _logger.Warning("Received initial message from client, but arguments was not set.");
                }
            }

            return(false);
        }
예제 #18
0
        /// <inheritdoc />
        public IEnumerable <TenantOffset> Get(IEnumerable <TenantId> tenants, EventHorizonKey key)
        {
            var offsets = new List <TenantOffset>();

            Parallel.ForEach(tenants, (tenant) =>
            {
                _executionContextManager.CurrentFor(tenant);
                using (var geodesics = _getGeodesics())
                {
                    var offset = geodesics.GetOffset(key);
                    offsets.Add(new TenantOffset(tenant, offset));
                }
            });
            return(offsets);
        }
예제 #19
0
 void ProcessInParallel()
 {
     //_logger.Information("Process")
     Parallel.ForEach(_systemsThatKnowAboutEventProcessors.ToList(), (system) =>
     {
         Parallel.ForEach(system.ToList(), (processor) =>
         {
             Parallel.ForEach(_tenants.All, (t) =>
             {
                 _executionContextManager.CurrentFor(t, CorrelationId.New(), Claims.Empty);
                 _processingHub.Register(new ScopedEventProcessor(t, processor, _getOffsetRepository, _getUnprocessedEventsFetcher, _logger));
             });
         });
     });
 }
예제 #20
0
 public void Perform()
 {
     _tenants.All.ForEach(tenant => {
         Task.Factory.StartNew(() => {
             try
             {
                 _contextManager.CurrentFor(tenant);
                 _configurationManagerFactory().Start();
             }
             catch (Exception e)
             {
                 _logger.Error(e, $"Error while startig identity provider configuration manager for tenant '{tenant}'. No providers will be available for that tenant.");
             }
         });
     });
 }
        /// <inheritdoc />
        public void HandleWebhookPayload(ActivityPayload payload, Guid deliveryId)
        {
            if (_registeredHandlers.TryGetValue(payload.GetType(), out var handlers))
            {
                // Figure out the execution context for this event
                var tenantId = _tenantMapper.GetTenantFor(payload.Installation);
                _executionContextManager.CurrentFor(tenantId, deliveryId);

                // Schedule the event for processing
                var scheduler = _schedulerFactory();
                foreach (var handler in handlers)
                {
                    scheduler.QueueWebhookEventForHandling(handler.Type, handler.Method, payload);
                }
            }
        }
예제 #22
0
        /// <inheritdoc/>
        public QueryResult Execute(TenantId tenant, IQuery query)
        {
            _executionContextManager.CurrentFor(tenant);
            var instance = _container.Get(query.GetType()) as IQuery;

            foreach (var property in query.GetType().GetProperties())
            {
                if (!property.Name.Equals("Query", StringComparison.InvariantCulture))
                {
                    property.SetValue(instance, property.GetValue(query));
                }
            }

            return(_runtimeQueryCoordinator.Execute(instance, new PagingInfo {
                Number = 0, Size = int.MaxValue
            }).Result);
        }
예제 #23
0
        public IActionResult SignUserInTo(HttpContext context, TenantId tenant, string redirectUri)
        {
            var authResult = context.AuthenticateAsync(Constants.ExternalCookieSchemeName).Result;

            if (authResult.Succeeded)
            {
                var userTenants = _mapper.GetTenantsFor(authResult.Principal);
                foreach (var userTenant in userTenants)
                {
                    if (userTenant == tenant)
                    {
                        _manager.CurrentFor(tenant);
                        return(SetTenantCredentialsFor(context, _userMapperFactory(), authResult.Principal, redirectUri));
                    }
                }
            }
            return(new UnauthorizedResult());
        }
        async Task OnReceivedRequest(
            Func <TRequest, CancellationToken, Task <TResponse> > callback,
            TRequest request,
            CancellationToken cancellationToken)
        {
            try
            {
                var       requestContext = _getRequestContext(request);
                var       callId         = requestContext.CallId.To <ReverseCallId>();
                TResponse response;
                try
                {
                    _logger.Trace("Handling request with call '{CallId}'", callId);
                    _executionContextManager.CurrentFor(requestContext.ExecutionContext);
                    response = await callback(request, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    _logger.Warning(ex, "An error occurred while invoking request handler callback for request '{CallId}'", callId);
                    return;
                }

                await _writeResponseSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);

                try
                {
                    await WriteResponse(response, callId, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    _logger.Warning(ex, "Error occurred while writing response for request '{CallId}'", callId);
                }
                finally
                {
                    _writeResponseSemaphore.Release();
                }
            }
            catch (Exception ex)
            {
                _logger.Warning(ex, "An error occurred while handling received request");
            }
        }
예제 #25
0
        /// <inheritdoc/>
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var stream = bindingContext.HttpContext.Request.Body;

            try
            {
                using (var buffer = new MemoryStream())
                {
                    await stream.CopyToAsync(buffer);

                    buffer.Position = 0L;

                    using (var reader = new StreamReader(buffer))
                    {
                        var json = await reader.ReadToEndAsync();

                        var commandRequestKeyValues = _serializer.GetKeyValuesFromJson(json);
                        var correlationId           = Guid.Parse(commandRequestKeyValues["correlationId"].ToString());
                        _executionContextManager.CurrentFor(TenantId.Unknown, correlationId);


                        var content = _serializer.GetKeyValuesFromJson(commandRequestKeyValues["content"].ToString());

                        var commandRequest = new CommandRequest(
                            Guid.Parse(commandRequestKeyValues["correlationId"].ToString()),
                            Guid.Parse(commandRequestKeyValues["type"].ToString()),
                            ArtifactGeneration.First,
                            content.ToDictionary(keyValue => keyValue.Key.ToPascalCase(), keyValue => keyValue.Value)

                            );

                        bindingContext.Result = ModelBindingResult.Success(commandRequest);
                    }

                    bindingContext.HttpContext.Request.Body = buffer;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
예제 #26
0
        /// <inheritdoc/>
        public async Task <SubscriptionResponse> Subscribe(TenantId consumerTenant, Subscription subscription, CancellationToken cancellationToken)
        {
            _executionContextManager.CurrentFor(consumerTenant);
            _logger.Debug("Subscribing to events from {Partition} in {Stream} of {ProducerTenant} in {Microservice} for {ConsumerTenant} into {Scope}", subscription.Partition, subscription.Stream, subscription.Tenant, subscription.Microservice, consumerTenant, subscription.Scope);
            var response = await _client.SubscribeAsync(
                new Contracts.Subscription
            {
                CallContext = new Services.Contracts.CallRequestContext
                {
                    HeadId           = _head.Id.ToProtobuf(),
                    ExecutionContext = _executionContextManager.Current.ToProtobuf(),
                },
                PartitionId    = subscription.Partition.ToProtobuf(),
                StreamId       = subscription.Stream.ToProtobuf(),
                TenantId       = subscription.Tenant.ToProtobuf(),
                MicroserviceId = subscription.Microservice.ToProtobuf(),
                ScopeId        = subscription.Scope.ToProtobuf()
            }, cancellationToken : cancellationToken);

            return(new SubscriptionResponse(response.ConsentId, response.Failure));
        }
예제 #27
0
        void GatherAllEventProcessors()
        {
            _logger.Information("Gather all event processors");

            _scheduler.PerformForEach(_systemsThatKnowAboutEventProcessors, (system) =>
            {
                _logger.Information($"System that knows about event processors : {system.GetType().AssemblyQualifiedName}");

                _scheduler.PerformForEach(system, (processor) =>
                {
                    _logger.Information($"Processor : {processor.GetType().AssemblyQualifiedName}");

                    _scheduler.PerformForEach(_tenants.All, (t) =>
                    {
                        _logger.Information($"Register scoped event processor for tenant : {t}");
                        _executionContextManager.CurrentFor(t, CorrelationId.New(), Claims.Empty);
                        _processingHub.Register(new ScopedEventProcessor(t, processor, _getOffsetRepository, _getUnprocessedEventsFetcher, _logger));
                    });
                });
            });
        }
예제 #28
0
        /// <summary>
        /// Injects an event
        /// </summary>
        public void InjectEvent(TenantId tenant, EventSourceId eventSourceId, IEvent @event)
        {
            _logger.Information($"Injecting event!");

            _executionContextManager.CurrentFor(tenant);
            var executionContext = _executionContextManager.Current;

            using (var eventStore = _getEventStore())
            {
                var artifact       = _artifactTypeMap.GetArtifactFor(@event.GetType());
                var eventSourceKey = new EventSourceKey(eventSourceId, artifact.Id);
                var version        = eventStore.GetNextVersionFor(eventSourceKey);

                var uncommittedEventStream = new UncommittedEventStream(
                    CommitId.New(),
                    executionContext.CorrelationId,
                    new VersionedEventSource(version, eventSourceKey),
                    DateTimeOffset.Now,
                    EventStream.From(new [] {
                    new EventEnvelope(
                        new EventMetadata(
                            EventId.New(),
                            new VersionedEventSource(version, eventSourceKey),
                            executionContext.CorrelationId,
                            artifact,
                            DateTimeOffset.Now,
                            executionContext
                            ),
                        @event.ToPropertyBag()
                        )
                })
                    );

                _logger.Information("Commit events to store");
                var committedEventStream = eventStore.Commit(uncommittedEventStream);

                _logger.Information("Process committed events");
                _processingHub.Process(committedEventStream);
            }
        }
예제 #29
0
 public void Replay <T>(
     IEnumerable <T> events,
     Func <T, Guid> getIdCallback,
     Action <IEventSource, T> eventSourceCallback = null) where T : IEvent
 {
     _executionContextManager.CurrentFor(TenantId.Unknown);
     events.ForEach(@event => {
         try
         {
             var eventSource = new ExternalSource(getIdCallback(@event));
             eventSource.Apply(@event);
             if (eventSourceCallback != null)
             {
                 eventSourceCallback(eventSource, @event);
             }
             _uncommittedEventStreamCoordinator.Commit(CorrelationId.New(), eventSource.UncommittedEvents);
         } catch (Exception exception)
         {
             _logger.Error(exception, "Problem applying event");
         }
     });
 }
예제 #30
0
        /// <summary>
        /// Handle a command
        /// </summary>
        /// <param name="json">JSON representation of a <see cref="CommandRequest"/></param>
        /// <returns><see cref="CommandResult"/></returns>
        public CommandResult Handle(string json)
        {
            _logger.Information($"Handle : {json}");

            var commandRequestKeyValues = _serializer.GetKeyValuesFromJson(json);
            var correlationId           = Guid.Parse(commandRequestKeyValues["correlationId"].ToString());

            _executionContextManager.CurrentFor(TenantId.Development, correlationId);

            var content = _serializer.GetKeyValuesFromJson(commandRequestKeyValues["content"].ToString());

            var commandRequest = new CommandRequest(
                Guid.Parse(commandRequestKeyValues["correlationId"].ToString()),
                Guid.Parse(commandRequestKeyValues["type"].ToString()),
                ArtifactGeneration.First,
                content.ToDictionary(keyValue => keyValue.Key.ToPascalCase(), keyValue => keyValue.Value)
                );

            var result = _commandCoordinator.Handle(commandRequest);

            return(result);
        }