public void StatisticsHistoryFilter_ActsBefore_RetryFilter() { var statisticsHistoryFilter = new StatisticsHistoryAttribute(); var retryFilter = new AutomaticRetryAttribute(); Assert.True(statisticsHistoryFilter.Order > retryFilter.Order); }
public void OnStateElection_DoesNotChangeState_IfRetryAttemptsIsSetToZero() { var filter = new AutomaticRetryAttribute { Attempts = 0 }; filter.OnStateElection(_context.Object); Assert.Same(_failedState, _context.Object.CandidateState); }
public void DelaysInSeconds_SetsValueCorrectly() { var filter = new AutomaticRetryAttribute { DelaysInSeconds = new[] { 5, 8 } }; Assert.Equal(2, filter.DelaysInSeconds.Length); Assert.Equal(5, filter.DelaysInSeconds[0]); Assert.Equal(8, filter.DelaysInSeconds[1]); }
public void OnStateElection_ChangesStateToDeleted_IfRetryAttemptsNumberIsZeroAndOnAttemptsExceedIsSetToDelete() { _connection.Setup(x => x.GetJobParameter(JobId, "RetryCount")).Returns("0"); var filter = new AutomaticRetryAttribute { Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete }; filter.OnStateElection(_context.Object); Assert.IsType <DeletedState>(_context.Object.CandidateState); }
public void OnStateElection_UsesDelaysInSeconds_WhenBothDelaysInSecondsAndDelayInSecondsByAttemptFuncAreSpecified() { var filter = new AutomaticRetryAttribute { DelayInSecondsByAttemptFunc = attempt => 1, DelaysInSeconds = new[] { 0 } }; filter.OnStateElection(_context.Object); Assert.IsType <EnqueuedState>(_context.Object.CandidateState); }
public void DelayInSecondsByAttemptFunc_ReturnCorrectValue_WhenCustomFunctionIsSet() { var filter = new AutomaticRetryAttribute { DelayInSecondsByAttemptFunc = attempt => (int)attempt % 3 }; Assert.Equal(1, filter.DelayInSecondsByAttemptFunc(1)); Assert.Equal(2, filter.DelayInSecondsByAttemptFunc(2)); Assert.Equal(0, filter.DelayInSecondsByAttemptFunc(3)); Assert.Equal(1, filter.DelayInSecondsByAttemptFunc(4)); Assert.Equal(2, filter.DelayInSecondsByAttemptFunc(5)); Assert.Equal(1, filter.DelayInSecondsByAttemptFunc(100)); }
public void OnStateElection_ChangeStateToEnqueued_IfDelayIsZero() { var filter = new AutomaticRetryAttribute { Attempts = 1, DelaysInSeconds = new[] { 0 } }; filter.OnStateElection(_context.Object); Assert.IsType <EnqueuedState>(_context.Object.CandidateState); Assert.NotNull(_context.Object.CandidateState.Reason); Assert.Contains("1 of 1", _context.Object.CandidateState.Reason); _connection.Verify(x => x.SetJobParameter(JobId, "RetryCount", "1")); }
public void OnStateElection_ThrowsAnException_WhenDelayInSecondsByAttemptFuncThrowsAnException() { var exception = new Exception(); var filter = new AutomaticRetryAttribute { DelayInSecondsByAttemptFunc = attempt => { throw exception; } }; var thrownExcetption = Assert.Throws <Exception>(() => filter.OnStateElection(_context.Object)); Assert.Equal(exception, thrownExcetption); }
public void Ctor_SetsPositiveRetryAttemptsNumber_ByDefault() { var filter = new AutomaticRetryAttribute(); Assert.Equal(10, filter.Attempts); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var env = new Env(); ConfigureRateLimiting(services); if (env.IsDevelopment) { DotEnv.Config(true, ".env.development"); } services.AddSingleton <CdsServiceClientWrapper, CdsServiceClientWrapper>(); services.AddTransient <IOrganizationService>(sp => sp.GetService <CdsServiceClientWrapper>().CdsServiceClient?.Clone()); services.AddTransient <IOrganizationServiceAdapter, OrganizationServiceAdapter>(); services.AddTransient <ICrmService, CrmService>(); services.AddScoped <IStore, Store>(); services.AddScoped <DbConfiguration, DbConfiguration>(); services.AddSingleton <IMetricService, MetricService>(); services.AddSingleton <INotificationClientAdapter, NotificationClientAdapter>(); services.AddSingleton <IGeocodeClientAdapter, GeocodeClientAdapter>(); services.AddSingleton <ICandidateAccessTokenService, CandidateAccessTokenService>(); services.AddSingleton <ICandidateMagicLinkTokenService, CandidateMagicLinkTokenService>(); services.AddSingleton <INotifyService, NotifyService>(); services.AddSingleton <IClientManager, ClientManager>(); services.AddSingleton <IHangfireService, HangfireService>(); services.AddSingleton <IRedisService, RedisService>(); services.AddSingleton <IPerformContextAdapter, PerformContextAdapter>(); services.AddSingleton <ICallbackBookingService, CallbackBookingService>(); services.AddSingleton <IEnv>(env); var connectionString = DbConfiguration.DatabaseConnectionString(env); services.AddDbContext <GetIntoTeachingDbContext>(b => DbConfiguration.ConfigPostgres(connectionString, b)); services.AddAuthentication("ApiClientHandler") .AddScheme <ApiClientSchemaOptions, ApiClientHandler>("ApiClientHandler", op => { }); services.AddControllers(o => { o.ModelBinderProviders.Insert(0, new TrimStringModelBinderProvider()); }) .AddFluentValidation(c => { c.RegisterValidatorsFromAssemblyContaining <Startup>(); }) .AddJsonOptions(o => { o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); o.JsonSerializerOptions.Converters.Add(new TrimStringJsonConverter()); o.JsonSerializerOptions.Converters.Add(new EmptyStringToNullJsonConverter()); }); services.Configure <KestrelServerOptions>(options => { // Workaround for https://github.com/dotnet/aspnetcore/issues/8302 // caused by Prometheus.HttpMetrics.HttpRequestDurationMiddleware options.AllowSynchronousIO = true; }); services.AddSwaggerGen(c => { c.SwaggerDoc( "v1", new OpenApiInfo { Title = "Get into Teaching API - V1", Version = "v1", Description = @" Provides a RESTful API for integrating with the Get into Teaching CRM. The Get into Teaching (GIT) API sits in front of the GIT CRM, which uses the [Microsoft Dynamics365](https://docs.microsoft.com/en-us/dynamics365/) platform (the [Customer Engagement](https://docs.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/overview) module is used for storing Candidate information and the [Marketing](https://docs.microsoft.com/en-us/dynamics365/marketing/developer/using-events-api) module for managing Events). The GIT API aims to provide: * Simple, task-based RESTful APIs. * Message queueing (while the GIT CRM is offline for updates). * Validation to ensure consistency across services writing to the GIT CRM. ", License = new OpenApiLicense { Name = "MIT License", Url = new Uri("https://opensource.org/licenses/MIT"), }, }); c.AddSecurityDefinition("apiKey", new OpenApiSecurityScheme { Type = SecuritySchemeType.ApiKey, Name = "Authorization", In = ParameterLocation.Header, }); c.OperationFilter <AuthOperationFilter>(); c.EnableAnnotations(); c.AddFluentValidationRules(); }); services.AddHangfire((provider, config) => { var automaticRetry = new AutomaticRetryAttribute { Attempts = JobConfiguration.Attempts(env), DelaysInSeconds = new[] { JobConfiguration.RetryIntervalInSeconds(env) }, OnAttemptsExceeded = AttemptsExceededAction.Delete, }; config .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) .UseSimpleAssemblyNameTypeSerializer() .UseRecommendedSerializerSettings() .UseFilter(automaticRetry); if (env.IsTest) { config.UseMemoryStorage().WithJobExpirationTimeout(JobConfiguration.ExpirationTimeout); } else { config.UsePostgreSqlStorage(DbConfiguration.HangfireConnectionString(env)); } }); }
public void OnStateElection_ChangesStateToDeleted_IfRetryAttemptsNumberExceededAndOnAttemptsExceededIsSetToDelete() { _connection.Setup(x => x.GetJobParameter(JobId, "RetryCount")).Returns("1"); var filter = new AutomaticRetryAttribute { Attempts = 1, OnAttemptsExceeded = AttemptsExceededAction.Delete }; filter.OnStateElection(_context.Object); Assert.IsType<DeletedState>(_context.Object.CandidateState); }
public void Ctor_SetsOnAttemptsExceededAction_ByDefault() { var filter = new AutomaticRetryAttribute(); Assert.Equal(AttemptsExceededAction.Fail, filter.OnAttemptsExceeded); }
public void Ctor_DelayByAttemptIsNotNull_ByDefault() { var filter = new AutomaticRetryAttribute(); Assert.NotNull(filter.DelayInSecondsByAttemptFunc); }
/// <summary> /// Initialises a new instance of the <see cref="TaskAutomaticRetryJobFilter" /> class. /// </summary> /// <param name="defaultAutomaticRetryAttribute">The default registered <see cref="AutomaticRetryAttribute" /> that /// will be applied.</param> public TaskAutomaticRetryJobFilter(AutomaticRetryAttribute defaultAutomaticRetryAttribute) { this._defaultAutomaticRetryAttribute = defaultAutomaticRetryAttribute; }