internal ServiceCommand(IJellyfishContext context, IClock clock, string commandGroup = null, string commandName = null, string threadPoolKey = null, CommandPropertiesBuilder properties = null, ICircuitBreaker circuitBreaker = null, CommandMetrics metrics = null, CommandExecutionHook executionHook = null)
        {
            Contract.Requires(context != null);
            CommandState state = _states.GetOrAdd(this.GetType().FullName, (n) => ServiceCommandHelper.PrepareInternal(this.GetType(), context, commandGroup, commandName, properties, clock, metrics, circuitBreaker));

            if (String.IsNullOrEmpty(state.CommandGroup))
            {
                throw new ArgumentException("commandGroup can not be null or empty.");
            }

            Logger = context.GetService <ILoggerFactory>()?.CreateLogger(this.GetType().FullName) ?? EmptyLogger.Instance;

            CommandGroup    = state.CommandGroup;
            CommandName     = state.CommandName;
            _clock          = clock ?? Clock.GetInstance(); // for test
            Properties      = properties?.Build(CommandName) ?? new CommandProperties(CommandName);
            Metrics         = metrics ?? CommandMetricsFactory.GetInstance(CommandName, CommandGroup, Properties, _clock);
            _circuitBreaker = circuitBreaker ?? (Properties.CircuitBreakerEnabled.Value ? CircuitBreakerFactory.GetOrCreateInstance(CommandName, Properties, Metrics, _clock) : new NoOpCircuitBreaker());
            context.MetricsPublisher.CreateOrRetrievePublisherForCommand(CommandGroup, Metrics, _circuitBreaker);

            this._flags = state.Flags;

            _threadPoolKey   = threadPoolKey ?? CommandGroup;
            _executionResult = new ExecutionResult();
            _executionHook   = executionHook ?? context.CommandExecutionHook;

            var executionPolicy = Properties.ExecutionIsolationStrategy.Value;

            if (executionPolicy == ExecutionIsolationStrategy.Semaphore)
            {
                _flags |= ServiceCommandOptions.SemaphoreExecutionStrategy;
            }
            if (executionPolicy == ExecutionIsolationStrategy.Thread)
            {
                _flags |= ServiceCommandOptions.ThreadExecutionStrategy;
            }

            if (Properties.RequestLogEnabled.Value)
            {
                _currentRequestLog = context.GetRequestLog();
            }

            if ((_flags & ServiceCommandOptions.HasCacheKey) == ServiceCommandOptions.HasCacheKey && Properties.RequestCacheEnabled.Value)
            {
                _requestCache = context.GetCache <CacheItem>(CommandName);
            }
        }