public void The_default_time_out_should_be_1_day() { TransportMessageHelpers.SetHeader(_message, SecondLevelRetriesHeaders.RetriesTimestamp, DateTimeExtensions.ToWireFormattedString(DateTime.UtcNow.AddDays(-1).AddSeconds(-1))); var hasTimedOut = DefaultRetryPolicy.RetryPolicy(_message) == TimeSpan.MinValue; Assert.IsTrue(hasTimedOut); }
public void TestLargeRetryCount() { var maxRetries = 1000; var maxMilliseconds = 1; ClientConfig config = new AmazonDynamoDBConfig(); config.MaxErrorRetry = 100; var coreRetryPolicy = new DefaultRetryPolicy(config) { MaxBackoffInMilliseconds = maxMilliseconds }; var ddbRetryPolicy = new DynamoDBRetryPolicy(config) { MaxBackoffInMilliseconds = maxMilliseconds }; var context = new ExecutionContext(new RequestContext(false), null); for (int i = 0; i < maxRetries; i++) { context.RequestContext.Retries = i; coreRetryPolicy.WaitBeforeRetry(context); ddbRetryPolicy.WaitBeforeRetry(context); } }
public void LogsMessage() { using var logger = new FellerConsoleLogger() { CategoryName = GetType().FullName.ToString() }; var timeOfLogCall = DateTime.Now; logger.LogInformation("Test message {TestValueA} {TestValueB}", 0.001, PrimaryColours.Red.ToString()); string log = null; DefaultRetryPolicy.Execute(() => { log = _consoleOutput.GetOuptut(); return(!string.IsNullOrEmpty(log)); }); var deserialiedLog = JObject.Parse(log); Assert.IsTrue((timeOfLogCall - deserialiedLog.Value <DateTime>("Timestamp")).TotalMilliseconds < 5); Assert.AreEqual(0.001, deserialiedLog.Value <double>("TestValueA")); Assert.AreEqual(PrimaryColours.Red.ToString(), deserialiedLog.Value <string>("TestValueB")); Assert.AreEqual("Test message 0.001 Red", deserialiedLog.Value <string>("Message")); Assert.AreEqual(2, deserialiedLog.Value <int>("Level")); Assert.AreEqual("Feller.Tests.FellerConsoleLoggerTests", deserialiedLog.Value <string>("CategoryName")); }
internal Gateway() { DependsOn("NServiceBus.Features.DelayedDeliveryFeature"); Defaults(s => s.SetDefault("Gateway.Retries.RetryPolicy", DefaultRetryPolicy.BuildWithDefaults())); // since the installers are registered even if the feature isn't enabled we need to make // this a no-op if the installer runs without the feature enabled Defaults(c => c.Set <InstallerSettings>(new InstallerSettings())); }
public void TestRetriesOnException <T>(T exception) where T : AmazonServiceException { var webIdentityToken = "Dummy.OIDC.Token"; var roleArn = "someRoleArn"; var roleSessionName = "someRoleSessionName"; var currentDirectory = Directory.GetCurrentDirectory(); var webIdentityTokenFilePath = Path.Combine(currentDirectory, "my-token.jwt"); File.WriteAllText(webIdentityTokenFilePath, webIdentityToken); var envVariables = new Dictionary <string, string>() { { AssumeRoleWithWebIdentityCredentials.WebIdentityTokenFileEnvVariable, webIdentityTokenFilePath }, { AssumeRoleWithWebIdentityCredentials.RoleArnEnvVariable, roleArn }, { AssumeRoleWithWebIdentityCredentials.RoleSessionNameEnvVariable, roleSessionName }, }; AWSCredentials awsCredentials; using (new FallbackFactoryTestFixture(envVariables)) { awsCredentials = FallbackCredentialsFactory.GetCredentials(); } var webIdentityCredentials = new AssumeRoleWithWebIdentityTestCredentials((AssumeRoleWithWebIdentityCredentials)awsCredentials, null); var retries = 0; var client = webIdentityCredentials.Client as AmazonSecurityTokenServiceClient; var pipeline = client .GetType() .GetProperty("RuntimePipeline", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) .GetValue(client, null) as RuntimePipeline; // Setup STS failures var credentialsRetriever = new Mock <CredentialsRetriever>(awsCredentials); credentialsRetriever.Setup(cr => cr.InvokeSync(It.IsAny <IExecutionContext>())).Throws(exception); // Setting up the exception here pipeline.ReplaceHandler <CredentialsRetriever>(credentialsRetriever.Object); // Setup retry count notifications var retryHandler = pipeline.Handlers.Find(h => h is RetryHandler) as RetryHandler; var notifyingRetryHandler = new NotifyingRetryHandler(client.Config); notifyingRetryHandler.AddHandler((object sender, RetryEventArgs e) => { retries++; }); pipeline.ReplaceHandler <RetryHandler>(notifyingRetryHandler); var defaultRetryPolicy = new DefaultRetryPolicy(client.Config); using (new FallbackFactoryTestFixture(envVariables)) { // Act and Assert Assert.ThrowsException <AmazonClientException>(() => webIdentityCredentials.GetCredentials()); } Assert.AreEqual(defaultRetryPolicy.MaxRetries, retries); webIdentityCredentials.Dispose(); }
public void The_time_span_should_increase_with_10_sec_for_every_retry() { for (int i = 0; i < 3; i++) { var timeSpan = DefaultRetryPolicy.RetryPolicy(_message); Defer(); Assert.AreEqual(_expectedResults[i], timeSpan.Seconds); } }
public CloudWatchSink( int defaultInterval, IPlugInContext context, IAmazonCloudWatch cloudWatchClient ) : this(defaultInterval, context) { // Setup Client CloudWatchClient = cloudWatchClient; // Setup Default Retry Policy _defaultRetryPolicy = new DefaultRetryPolicy(CloudWatchClient.Config); }
public void non_transient_exception_is_not_retried() { using var conn = new NpgsqlConnection(ConnectionSource.ConnectionString); conn.Open(); var retryPolicy = DefaultRetryPolicy.Times(1, sleep: x => TimeSpan.FromMilliseconds(20)); var retryPolicyDecorator = RetryPolicyDecorator.For(retryPolicy, runNumber => throw createNpgsqlException(false)); Should.Throw <NpgsqlException>(() => retryPolicyDecorator.Execute(() => conn.CreateCommand().ExecuteNonQuery())); retryPolicyDecorator.ExecutionCount.ShouldBe(1); }
public void transient_exception_is_retried_but_throws_eventually() { using var conn = new NpgsqlConnection(ConnectionSource.ConnectionString); conn.Open(); var retryPolicy = DefaultRetryPolicy.Twice(sleep: x => TimeSpan.FromMilliseconds(20)); var retryPolicyDecorator = RetryPolicyDecorator.For(retryPolicy, runNumber => throw createNpgsqlException(true)); Should.Throw <NpgsqlException>(() => retryPolicyDecorator.Execute(() => conn.CreateCommand("").ExecuteNonQuery())); retryPolicyDecorator.ExecutionCount.ShouldBe(3); }
public async Task ExecuteAsync_ResponseOk_DoesNotRetry() { var options = new DefaultRetryPolicyOptions { DeltaBackoff = TimeSpan.FromSeconds(5) }; var retryPolicy = new DefaultRetryPolicy(options); var client = new FakeSender().Returns(HttpStatusCode.OK); var response = await retryPolicy.ExecuteAsync(client.SendRequest); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(1, client.TimesCalled); }
public void TestInvalidMaxRetryTimes() { try { RetryPolicy policy = new DefaultRetryPolicy(-1, 0); Assert.Fail(); } catch (OTSClientException) { } try { RetryPolicy policy = new DefaultRetryPolicy(-1000, 0); Assert.Fail(); } catch (OTSClientException) { } }
public void Should_wait_and_execute_retry_action() { // Arrange var are = new AutoResetEvent(false); var policy = new DefaultRetryPolicy(); // Action policy.WaitForNextRetry(() => are.Set()); Assert.IsTrue(are.WaitOne(1000)); // Assert Assert.AreEqual(1000, policy.DelayTime); Assert.IsFalse(policy.IsWaiting); }
public async Task ExecuteAsync_ThrottledRequest_NoHeader_GetsNextWaitTime(HttpStatusCode statusCode) { var options = new DefaultRetryPolicyOptions { DeltaBackoff = TimeSpan.FromSeconds(10), MaxCumulativeWaitTime = TimeSpan.FromSeconds(5) }; var retryPolicy = new DefaultRetryPolicy(options); var client = new FakeSender().Returns(statusCode); var response = await retryPolicy.ExecuteAsync(client.SendRequest); Assert.Equal(statusCode, response.StatusCode); Assert.Equal(1, client.TimesCalled); }
public void Should_reset_delay_time_to_0() { // Arrange var are = new AutoResetEvent(false); var policy = new DefaultRetryPolicy(); policy.WaitForNextRetry(() => are.Set()); are.WaitOne(); // Action policy.Reset(); // Assert Assert.AreEqual(0, policy.DelayTime); Assert.IsFalse(policy.IsWaiting); }
public void non_transient_exception_is_not_retried() { var retryPolicy = DefaultRetryPolicy.Times(1, sleep: x => TimeSpan.FromMilliseconds(20)); var retryPolicyDecorator = RetryPolicyDecorator.For(retryPolicy, runNumber => throw createNpgsqlException(false)); using var connection = new ManagedConnection(new ConnectionSource(), retryPolicyDecorator); var cmd = new NpgsqlCommand(); Exception <NpgsqlException> .ShouldBeThrownBy(() => connection.Execute(cmd)); retryPolicyDecorator.ExecutionCount.ShouldBe(1); cmd.Dispose(); connection.Dispose(); }
private const int FLUSH_QUEUE_DELAY = 100; //Throttle at about 10 TPS public CloudWatchSink(int defaultInterval, IPlugInContext context, IAmazonCloudWatch cloudWatchClient) : base(defaultInterval, context) { _cloudWatchClient = cloudWatchClient; _defaultRetryPolicy = new DefaultRetryPolicy(_cloudWatchClient.Config); //StorageResolution is used to specify standard or high-resolution metrics. Valid values are 1 and 60 //It is different to interval. //See https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html for full details _storageResolution = base._interval < 60 ? 1 : 60; string dimensionsConfig = null; if (_config != null) { dimensionsConfig = _config["dimensions"]; _namespace = _config["namespace"]; } if (!string.IsNullOrEmpty(dimensionsConfig)) { List <Dimension> dimensions = new List <Dimension>(); string[] dimensionPairs = dimensionsConfig.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (var dimensionPair in dimensionPairs) { string[] keyValue = dimensionPair.Split('='); string value = ResolveVariables(keyValue[1]); dimensions.Add(new Dimension() { Name = keyValue[0], Value = value }); } _dimensions = dimensions.ToArray(); } else { _dimensions = DefaultDimensions; } if (string.IsNullOrEmpty(_namespace)) { _namespace = "KinesisTap"; } else { _namespace = ResolveVariables(_namespace); } }
public void CanPlugInRetryPolicyThatRetriesOnException() { var m = new List <string>(); StoreOptions(c => { #region sample_retrypolicy-samplepolicy-pluggingin // Plug in our custom retry policy via StoreOptions // We retry operations twice if they yield and NpgsqlException that is transient c.RetryPolicy(ExceptionFilteringRetryPolicy.Twice(e => e is NpgsqlException ne && ne.IsTransient)); #endregion sample_retrypolicy-samplepolicy-pluggingin #region sample_retrypolicy-samplepolicy-default // Use DefaultRetryPolicy which handles Postgres's transient errors by default with sane defaults // We retry operations twice if they yield and NpgsqlException that is transient // Each error will cause sleep of N seconds where N is the current retry number c.RetryPolicy(DefaultRetryPolicy.Twice()); #endregion sample_retrypolicy-samplepolicy-default // For unit test, use one that checks that exception is not transient c.RetryPolicy(ExceptionFilteringRetryPolicy.Twice(e => e is NpgsqlException ne && !ne.IsTransient)); // For unit test, override the policy with one that captures messages c.RetryPolicy(ExceptionFilteringRetryPolicy.Twice(e => { if (e is NpgsqlException ne && !ne.IsTransient) { m.Add(e.Message); return(true); } return(false); })); }); using (var s = theStore.QuerySession()) { Assert.Throws <Marten.Exceptions.MartenCommandException>(() => { var _ = s.Query <object>("select null from mt_nonexistenttable").FirstOrDefault(); }); } // Our retry exception filter should have triggered twice Assert.True(m.Count(s => s.IndexOf("relation \"mt_nonexistenttable\" does not exist", StringComparison.OrdinalIgnoreCase) > -1) == 2); }
public async Task transient_exception_is_retried() { using var conn = new NpgsqlConnection(ConnectionSource.ConnectionString); await conn.OpenAsync(); var retryPolicy = DefaultRetryPolicy.Times(1, sleep: x => TimeSpan.FromMilliseconds(20)); var retryPolicyDecorator = RetryPolicyDecorator.For(retryPolicy, runNumber => { if (runNumber == 1) { throw createNpgsqlException(true); } }); await retryPolicyDecorator.ExecuteAsync(() => conn.CreateCommand("select 1").ExecuteNonQueryAsync(), default); retryPolicyDecorator.ExecutionCount.ShouldBe(2); }
public async Task ExecuteAsync_ThrottledRequest_RetryAfterHeaderWithNotPositiveDelta_GetsNextWaitTime(HttpStatusCode statusCode, int waitTimeInSeconds) { var options = new DefaultRetryPolicyOptions { DeltaBackoff = TimeSpan.FromSeconds(10), MaxCumulativeWaitTime = TimeSpan.FromSeconds(5) }; var retryPolicy = new DefaultRetryPolicy(options); var mockResponse = new HttpResponseMessage(statusCode); mockResponse.Headers.RetryAfter = new RetryConditionHeaderValue(TimeSpan.FromSeconds(waitTimeInSeconds)); var client = new FakeSender().Returns(mockResponse); var response = await retryPolicy.ExecuteAsync(client.SendRequest); Assert.Equal(statusCode, response.StatusCode); Assert.Equal(1, client.TimesCalled); }
public async Task ExecuteAsync_ThrottledRequest_RetryAfterHeaderWithDate_ReadsWaitTimeFromHeader(HttpStatusCode statusCode) { var options = new DefaultRetryPolicyOptions { DeltaBackoff = TimeSpan.FromMilliseconds(100), MaxCumulativeWaitTime = TimeSpan.FromSeconds(5) }; var retryPolicy = new DefaultRetryPolicy(options); var mockResponse = new HttpResponseMessage(statusCode); mockResponse.Headers.RetryAfter = new RetryConditionHeaderValue(DateTime.UtcNow.AddSeconds(6)); var client = new FakeSender().Returns(mockResponse); var response = await retryPolicy.ExecuteAsync(client.SendRequest); Assert.Equal(statusCode, response.StatusCode); Assert.Equal(1, client.TimesCalled); }
public async Task ExecuteAsync_RecoversAfterNotSuccessStatusCode() { var options = new DefaultRetryPolicyOptions { DeltaBackoff = TimeSpan.FromMilliseconds(100) }; var retryPolicy = new DefaultRetryPolicy(options); var client = new FakeSender().Returns(HttpStatusCode.InternalServerError, HttpStatusCode.OK); var stopwatch = Stopwatch.StartNew(); var response = await retryPolicy.ExecuteAsync(client.SendRequest); stopwatch.Stop(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(2, client.TimesCalled); Assert.True(stopwatch.Elapsed > 0.8 * options.DeltaBackoff); }
public void Should_double_delay_time_until_max_delay_value_is_reached() { // Arrange var are = new AutoResetEvent(false); var policy = new DefaultRetryPolicy(1000 * 2 /* 2 seconds */); // Action policy.WaitForNextRetry(() => are.Set()); Assert.IsTrue(are.WaitOne(3000)); policy.WaitForNextRetry(() => are.Set()); Assert.IsTrue(are.WaitOne(6000)); policy.WaitForNextRetry(() => are.Set()); Assert.IsTrue(are.WaitOne(12000)); // Assert Assert.AreEqual(2000, policy.DelayTime); Assert.IsFalse(policy.IsWaiting); }
public void Should_double_delay_time_for_next_retry() { // Arrange var are = new AutoResetEvent(false); var policy = new DefaultRetryPolicy(); // Action policy.WaitForNextRetry(() => are.Set()); Assert.IsTrue(are.WaitOne(3000)); policy.WaitForNextRetry(() => are.Set()); Assert.IsTrue(are.WaitOne(6000)); policy.WaitForNextRetry(() => are.Set()); Assert.IsTrue(are.WaitOne(12000)); // Assert Assert.AreEqual(4000, policy.DelayTime); Assert.IsFalse(policy.IsWaiting); }
public async Task transient_exception_is_retried() { var retryPolicy = DefaultRetryPolicy.Times(1, sleep: x => TimeSpan.FromMilliseconds(20)); var retryPolicyDecorator = RetryPolicyDecorator.For(retryPolicy, runNumber => { if (runNumber == 1) { throw createNpgsqlException(true); } }); using var connection = new ManagedConnection(new ConnectionSource(), retryPolicyDecorator); var cmd = new NpgsqlCommand("select 1"); await connection.ExecuteAsync(cmd); retryPolicyDecorator.ExecutionCount.ShouldBe(2); cmd.Dispose(); connection.Dispose(); }
public async Task ExecuteAsync_RecoversAfterException() { var options = new DefaultRetryPolicyOptions { DeltaBackoff = TimeSpan.FromMilliseconds(100) }; var retryPolicy = new DefaultRetryPolicy(options); var client = new FakeSender() .Throws(GetExceptionFromStatus(WebExceptionStatus.ConnectionClosed)) .Returns(HttpStatusCode.OK); var stopwatch = Stopwatch.StartNew(); var response = await retryPolicy.ExecuteAsync(client.SendRequest); stopwatch.Stop(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(2, client.TimesCalled); Assert.True(stopwatch.Elapsed > 0.8 * options.DeltaBackoff); }
public async Task ExecuteAsync_Exception_RetriesUntilCumulativeWaitTimeReached() { var options = new DefaultRetryPolicyOptions { DeltaBackoff = TimeSpan.FromMilliseconds(100), MaxCumulativeWaitTime = TimeSpan.FromSeconds(2) }; var retryPolicy = new DefaultRetryPolicy(options); var client = new FakeSender().Throws(GetExceptionFromStatus(WebExceptionStatus.ConnectionClosed)); var stopwatch = Stopwatch.StartNew(); await Assert.ThrowsAsync <HttpRequestException>(() => retryPolicy.ExecuteAsync(client.SendRequest)); stopwatch.Stop(); Assert.True(client.TimesCalled > 1); var maximumPossibleNextWaitTime = 1.2 * options.DeltaBackoff * Math.Pow(2, client.TimesCalled - 1); Assert.True(stopwatch.Elapsed > options.MaxCumulativeWaitTime - maximumPossibleNextWaitTime); }
public async Task ExecuteAsync_UnsuccessfulStatusCode_RetriesUntilCumulativeWaitTimeReached() { var options = new DefaultRetryPolicyOptions { DeltaBackoff = TimeSpan.FromMilliseconds(100), MaxCumulativeWaitTime = TimeSpan.FromSeconds(2) }; var retryPolicy = new DefaultRetryPolicy(options); var client = new FakeSender().Returns(HttpStatusCode.InternalServerError); var stopwatch = Stopwatch.StartNew(); var response = await retryPolicy.ExecuteAsync(client.SendRequest); stopwatch.Stop(); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.True(client.TimesCalled > 1); var maximumPossibleNextWaitTime = 1.2 * options.DeltaBackoff * Math.Pow(2, client.TimesCalled - 1); Assert.True(stopwatch.Elapsed > options.MaxCumulativeWaitTime - maximumPossibleNextWaitTime); }
protected override async Task <CredentialsRefreshState> GenerateNewCredentialsAsync() { string token = null; for (var retry = 0; retry <= AWSSDKUtils.DefaultMaxRetry; retry++) { try { using (var fileStream = new FileStream(WebIdentityTokenFile, FileMode.Open, FileAccess.Read)) // Using FileStream to support NetStandard 1.3 { using (var streamReader = new StreamReader(fileStream)) { token = await streamReader.ReadToEndAsync().ConfigureAwait(false); } } break; } catch (Exception e) { if (retry == AWSSDKUtils.DefaultMaxRetry) { _logger.Debug(e, $"A token could not be loaded from the WebIdentityTokenFile at {WebIdentityTokenFile}."); throw new InvalidOperationException("A token could not be loaded from the WebIdentityTokenFile.", e); } DefaultRetryPolicy.WaitBeforeRetry(retry, 1000); } } AssumeRoleImmutableCredentials credentials; using (var coreStsClient = CreateClient()) { credentials = await coreStsClient.CredentialsFromAssumeRoleWithWebIdentityAuthenticationAsync(token, RoleArn, RoleSessionName, _options).ConfigureAwait(false); // Will retry InvalidIdentityToken and IDPCommunicationError } _logger.InfoFormat("New credentials created using assume role with web identity that expire at {0}", credentials.Expiration.ToString("yyyy-MM-ddTHH:mm:ss.fffffffK", CultureInfo.InvariantCulture)); return(new CredentialsRefreshState(credentials, credentials.Expiration)); }
public void Should_SetLegacyProperties_When_PoliciesAreProvidedByDefaultProfile() { var lbp1 = new RoundRobinPolicy(); var sep1 = new ConstantSpeculativeExecutionPolicy(1000, 1); var lbp2 = new RoundRobinPolicy(); var sep2 = new ConstantSpeculativeExecutionPolicy(1000, 1); var retryPolicy = new DefaultRetryPolicy(); var retryPolicy2 = new DefaultRetryPolicy(); var cluster = Cluster.Builder() .AddContactPoint("127.0.0.1") .WithLoadBalancingPolicy(lbp1) .WithSpeculativeExecutionPolicy(sep1) .WithRetryPolicy(retryPolicy) .WithSocketOptions(new SocketOptions().SetReadTimeoutMillis(123)) .WithQueryOptions( new QueryOptions() .SetConsistencyLevel(ConsistencyLevel.All) .SetSerialConsistencyLevel(ConsistencyLevel.LocalSerial)) .WithExecutionProfiles(opt => opt .WithProfile("default", profile => profile .WithLoadBalancingPolicy(lbp2) .WithSpeculativeExecutionPolicy(sep2) .WithRetryPolicy(retryPolicy2) .WithConsistencyLevel(ConsistencyLevel.Quorum) .WithSerialConsistencyLevel(ConsistencyLevel.Serial) .WithReadTimeoutMillis(4412))) .Build(); Assert.AreSame(retryPolicy2, cluster.Configuration.Policies.ExtendedRetryPolicy); Assert.AreSame(retryPolicy2, cluster.Configuration.Policies.RetryPolicy); Assert.AreSame(sep2, cluster.Configuration.Policies.SpeculativeExecutionPolicy); Assert.AreSame(lbp2, cluster.Configuration.Policies.LoadBalancingPolicy); Assert.AreEqual(4412, cluster.Configuration.SocketOptions.ReadTimeoutMillis); Assert.AreEqual(ConsistencyLevel.Quorum, cluster.Configuration.QueryOptions.GetConsistencyLevel()); Assert.AreEqual(ConsistencyLevel.Serial, cluster.Configuration.QueryOptions.GetSerialConsistencyLevel()); }
public void LogsMessage() { using var logger = new FellerTestLogger() { CategoryName = GetType().FullName.ToString() }; var timeOfLogCall = DateTime.Now; logger.LogInformation("Test message {TestValueA} {TestValueB}", 0.001, PrimaryColours.Red.ToString()); DefaultRetryPolicy.Execute(() => FellerTestLogger.Logs.Count > 1); FellerTestLogger.Logs.TryDequeue(out var log); Assert.IsNotNull(log); Assert.IsNotNull(log.Fields); Assert.IsTrue(log.Fields.Count == 6); Assert.IsTrue((timeOfLogCall - log.Timestamp.Value).TotalMilliseconds < 5); Assert.AreEqual(0.001, log.Fields["TestValueA"]); Assert.AreEqual(PrimaryColours.Red.ToString(), log.Fields["TestValueB"]); Assert.AreEqual("Test message 0.001 Red", log.Fields["Message"]); Assert.AreEqual(LogLevel.Information, log.Fields["Level"]); }