internal static CommandState PrepareInternal(Type commandType, IJellyfishContext context, string commandGroup, string commandName, CommandPropertiesBuilder propertiesBuilder = null, IClock clock = null, CommandMetrics metrics = null, ICircuitBreaker circuitBreaker = null) { var state = new CommandState(); state.CommandName = commandName ?? commandType.FullName; state.CommandGroup = commandGroup ?? state.CommandName; clock = clock ?? Clock.GetInstance(); var properties = propertiesBuilder?.Build(state.CommandName) ?? new CommandProperties(state.CommandName); metrics = metrics ?? CommandMetricsFactory.GetInstance(state.CommandName, state.CommandGroup, properties, clock); circuitBreaker = circuitBreaker ?? (properties.CircuitBreakerEnabled.Value ? CircuitBreakerFactory.GetOrCreateInstance(state.CommandName, properties, metrics, clock) : new NoOpCircuitBreaker()); context.MetricsPublisher.CreateOrRetrievePublisherForCommand(state.CommandGroup, metrics, circuitBreaker); ServiceCommandOptions flags = ServiceCommandOptions.None; if (IsMethodImplemented(commandType, "GetFallback")) { flags |= ServiceCommandOptions.HasFallBack; } if (IsMethodImplemented(commandType, "GetCacheKey")) { flags |= ServiceCommandOptions.HasCacheKey; } state.Flags = flags; return(state); }
public TestServiceCommand(IJellyfishContext ctx, string name, CommandPropertiesBuilder builder, IClock clock = null, TestCircuitBreaker circuitBreaker = null, CommandExecutionHook executionHook = null) : base(ctx ?? new JellyfishContext(), clock, name, name, null, builder, circuitBreaker, circuitBreaker?.Metrics, executionHook: executionHook) { SetFlag(ServiceCommandOptions.HasFallBack, false); SetFlag(ServiceCommandOptions.HasCacheKey, false); Id = cx++; }
private static void InitializeServices(IJellyfishContext ctx, Assembly asm) { foreach(var t in asm.GetTypes()) { if(!typeof( IServiceCommandInfo ).IsAssignableFrom( t )) continue; var attr = t.GetCustomAttributes<CommandAttribute>( true ).FirstOrDefault(); ServiceCommandHelper.PrepareInternal( t, ctx, attr?.CommandGroup, attr?.CommandName ); } }
private static void InitializeServices(IJellyfishContext ctx, Assembly asm) { foreach (var t in asm.GetTypes()) { if (!typeof(IServiceCommandInfo).IsAssignableFrom(t)) { continue; } var attr = t.GetCustomAttributes <CommandAttribute>(true).FirstOrDefault(); ServiceCommandHelper.PrepareInternal(t, ctx, attr?.CommandGroup, attr?.CommandName); } }
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); } }
internal static CommandState PrepareInternal(Type commandType, IJellyfishContext context, string commandGroup, string commandName, CommandPropertiesBuilder propertiesBuilder=null, IClock clock = null, CommandMetrics metrics = null, ICircuitBreaker circuitBreaker = null) { var state = new CommandState(); state.CommandName = commandName ?? commandType.FullName; state.CommandGroup = commandGroup ?? state.CommandName; clock = clock ?? Clock.GetInstance(); var properties = propertiesBuilder?.Build( state.CommandName ) ?? new CommandProperties( state.CommandName ); metrics = metrics ?? CommandMetricsFactory.GetInstance( state.CommandName, state.CommandGroup, properties, clock ); circuitBreaker = circuitBreaker ?? ( properties.CircuitBreakerEnabled.Value ? CircuitBreakerFactory.GetOrCreateInstance( state.CommandName, properties, metrics, clock ) : new NoOpCircuitBreaker() ); context.MetricsPublisher.CreateOrRetrievePublisherForCommand( state.CommandGroup, metrics, circuitBreaker ); ServiceCommandOptions flags = ServiceCommandOptions.None; if(IsMethodImplemented( commandType, "GetFallback" )) flags |= ServiceCommandOptions.HasFallBack; if(IsMethodImplemented( commandType, "GetCacheKey" )) flags |= ServiceCommandOptions.HasCacheKey; state.Flags = flags; return state; }
// ignoring since this never ends ... useful for testing https://github.com/Netflix//issues/236 // [Fact] //public void testSuccessClosesCircuitWhenBusy() // { // Plugins.getInstance().registerCommandExecutionHook(new MyCommandExecutionHook()); // try { // performLoad(200, 0, 40); // performLoad(250, 100, 40); // performLoad(600, 0, 40); // } finally { // .reset(); // } // } async Task performLoad(IJellyfishContext ctx, int totalNumCalls, int errPerc, int waitMillis) { Random rnd = new Random(); for (int i = 0; i < totalNumCalls; i++) { //System.out.println(i); try { var err = rnd.NextDouble() * 100 < errPerc; TestCommand cmd = new TestCommand(ctx, err); await cmd.ExecuteAsync(); } catch (Exception) { //System.err.println(e.getMessage()); } Thread.Sleep(waitMillis); } }
internal MetricsPublisherFactory(IJellyfishContext context) { _context = context; }
public MyCommand(IJellyfishContext ctx, string id) : base(ctx) { _id = id; }
public static TestServiceCommand Get(IJellyfishContext ctx, ITestOutputHelper output, string commandName, ExecutionIsolationStrategy strategy, ExecutionResult executionResult = ExecutionResult.NONE, FallbackResult fallbackResult = FallbackResult.UNIMPLEMENTED, Action <CommandPropertiesBuilder> setter = null, TestCircuitBreaker circuitBreaker = null, IClock clock = null) { var builder = CommandPropertiesTest.GetUnitTestPropertiesSetter(); builder.WithExecutionIsolationStrategy(strategy); if (setter != null) { setter(builder); } if (clock == null) { clock = new MockedClock(); } var cmd = new TestServiceCommand(ctx, commandName, builder, clock, circuitBreaker ?? new TestCircuitBreaker(clock), new TestExecutionHook(output)); cmd.Log = msg => output.WriteLine("({0}) - {1}", cmd.Id, msg); if (executionResult == ExecutionResult.SUCCESS) { cmd.Action = () => { cmd.Log("Execution success"); return(Task.FromResult(TestCommandFactory.EXECUTE_VALUE)); }; } else if (executionResult == ExecutionResult.FAILURE) { cmd.Action = () => { cmd.Log("Execution failure");; throw new Exception("Execution Failure for TestCommand"); }; } else if (executionResult == ExecutionResult.HYSTRIX_FAILURE) { cmd.Action = () => { cmd.Log("Execution failure"); throw new Exception("Execution Failure for TestCommand", new Exception("Fallback Failure for TestCommand")); }; } else if (executionResult == ExecutionResult.RECOVERABLE_ERROR) { cmd.Action = () => { cmd.Log("Execution recoverable error"); throw new Exception("Execution ERROR for TestCommand"); }; } else if (executionResult == ExecutionResult.UNRECOVERABLE_ERROR) { cmd.Action = () => { cmd.Log("Execution unrecoverable error"); throw new StackOverflowException("Unrecoverable Error for TestCommand"); }; } else if (executionResult == ExecutionResult.BAD_REQUEST) { cmd.Action = () => { cmd.Log("Execution bad request"); throw new BadRequestException("Execution BadRequestException for TestCommand"); }; } if (fallbackResult == FallbackResult.SUCCESS) { cmd.Fallback = () => { cmd.Log("Execution fallback success"); return(Task.FromResult(TestCommandFactory.FALLBACK_VALUE)); }; } else if (fallbackResult == FallbackResult.FAILURE) { cmd.Fallback = () => { cmd.Log("Execution fallback error"); throw new Exception("Fallback Failure for TestCommand"); }; } else if (fallbackResult == FallbackResult.UNIMPLEMENTED) { cmd.Fallback = () => { cmd.Log("Execution fallback unimplemented"); throw new NotImplementedException(); }; } return(cmd); }
public SuccessfulCacheableCommand(IJellyfishContext ctx, TestCircuitBreaker circuitBreaker, bool cacheEnabled, T value) : base(ctx, circuitBreaker.Clock, "SuccessfulCacheableCommand", null, metrics: circuitBreaker.Metrics, circuitBreaker: circuitBreaker, properties: CommandPropertiesTest.GetUnitTestPropertiesSetter().WithRequestCacheEnabled(true)) { this.value = value; this.cacheEnabled = cacheEnabled; }
public TestController(IJellyfishContext ctx) { _context = ctx; }
/// <summary> /// Construct a <see cref="ServiceCommand{T}"/>. /// <p> /// The CommandName will be derived from the implementing class name. /// Construct a <see cref="ServiceCommand{T}"/> with defined <see cref="CommandPropertiesBuilder"/> that allows injecting property /// and strategy overrides and other optional arguments. /// <p> /// NOTE: The CommandName is used to associate a <see cref="ServiceCommand{T}"/> /// with <see cref="ICircuitBreaker"/>, <see cref="CommandMetrics"/> and other objects. /// <p> /// Do not create multiple <see cref="ServiceCommand{T}"/> implementations with the same CommandName /// but different injected default properties as the first instantiated will win. /// <p> /// Properties passed in via <see cref="CommandPropertiesBuilder">Properties</see> are cached for the given CommandName for the life of the Process /// or until <see cref="IJellyfishContext.Reset"/> is called. Dynamic properties allow runtime changes. Read more on the <a href="https://github.com/Zenasoft/Jellyfish.Configuration"> Wiki</a>. /// </summary> /// <param name="context">Current jellyfish context</param> /// <param name="commandGroup"> /// used to group together multiple <see cref="ServiceCommand{T}"/> objects. <p/> /// The CommandGroup is used to represent a common relationship between commands. /// For example, a library or team name, the system all related commands interact with, common business purpose etc. /// </param> /// <param name="properties"></param> /// <param name="threadPoolKey"> /// used to identify the thread pool in which a <see cref="ServiceCommand{T}"/> executes. /// </param> internal protected ServiceCommand(IJellyfishContext context, string commandGroup = null, string commandName = null, CommandPropertiesBuilder properties = null, string threadPoolKey = null, CommandExecutionHook executionHook = null) : this(context, null, commandGroup, commandName, threadPoolKey, properties) { }
public LatentCommand(IJellyfishContext ctx, int duration) : base(ctx, "Latent", null, new CommandPropertiesBuilder().WithExecutionTimeoutInMilliseconds(1000), null) { this.duration = duration; }
public TestCommand(IJellyfishContext ctx, bool error) : base(ctx ?? new JellyfishContext(), "group") { this.error = error; }