ServiceFabric: Service does not exist during deployment - error-handling

I have an existing system using service fabric. Everything is fine except during a service publish the service is unavailable and any resolutions return an error.
This is expected however it would be nice if during this time instead the calls just waited or timedout. During this time my error logs will sometimes fill up with 200K lines of the same error.
I want some code like the following however where would it go?
public async Task Execute(Func<Task> action)
{
try
{
action()
.ConfigureAwait(false);
}
catch (FabricServiceNotFoundException ex)
{
await Task.Delay(TimeSpan.FromSeconds(??))
.ConfigureAwait(false);
action()
.ConfigureAwait(false);
}
}
Error:
System.Fabric.FabricServiceNotFoundException: Service does not exist. ---> System.Runtime.InteropServices.COMException: Exception from HRESULT: 0x80071BCD
at System.Fabric.Interop.NativeClient.IFabricServiceManagementClient6.EndResolveServicePartition(IFabricAsyncOperationContext context)
at System.Fabric.FabricClient.ServiceManagementClient.ResolveServicePartitionEndWrapper(IFabricAsyncOperationContext context)
at System.Fabric.Interop.AsyncCallOutAdapter2`1.Finish(IFabricAsyncOperationContext context, Boolean expectedCompletedSynchronously)
--- End of inner exception stack trace ---
at Microsoft.ServiceFabric.Services.Client.ServicePartitionResolver.ResolveHelperAsync(Func`5 resolveFunc, ResolvedServicePartition previousRsp, TimeSpan resolveTimeout, TimeSpan maxRetryInterval, CancellationToken cancellationToken, Uri serviceUri)
at Microsoft.ServiceFabric.Services.Communication.Client.CommunicationClientFactoryBase`1.CreateClientWithRetriesAsync(ResolvedServicePartition previousRsp, TargetReplicaSelector targetReplicaSelector, String listenerName, OperationRetrySettings retrySettings, Boolean doInitialResolve, CancellationToken cancellationToken)
at Microsoft.ServiceFabric.Services.Communication.Client.CommunicationClientFactoryBase`1.GetClientAsync(ResolvedServicePartition previousRsp, TargetReplicaSelector targetReplica, String listenerName, OperationRetrySettings retrySettings, CancellationToken cancellationToken)
at Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Client.FabricTransportServiceRemotingClientFactory.GetClientAsync(ResolvedServicePartition previousRsp, TargetReplicaSelector targetReplicaSelector, String listenerName, OperationRetrySettings retrySettings, CancellationToken cancellationToken)
at Microsoft.ServiceFabric.Services.Communication.Client.ServicePartitionClient`1.GetCommunicationClientAsync(CancellationToken cancellationToken)
at Microsoft.ServiceFabric.Services.Communication.Client.ServicePartitionClient`1.InvokeWithRetryAsync[TResult](Func`2 func, CancellationToken cancellationToken, Type[] doNotRetryExceptionTypes)
at Microsoft.ServiceFabric.Services.Remoting.V2.Client.ServiceRemotingPartitionClient.InvokeAsync(IServiceRemotingRequestMessage remotingRequestMessage, String methodName, CancellationToken cancellationToken)
at Microsoft.ServiceFabric.Services.Remoting.Builder.ProxyBase.InvokeAsyncV2(Int32 interfaceId, Int32 methodId, String methodName, IServiceRemotingRequestMessageBody requestMsgBodyValue, CancellationToken cancellationToken)
at Microsoft.ServiceFabric.Services.Remoting.Builder.ProxyBase.ContinueWithResultV2[TRetval](Int32 interfaceId, Int32 methodId, Task`1 task)

As expected, Service Fabric have to shutdown the service to start the new version, this will cause a transient error like the one you've got.
By default, the Remoting APIs already have a retry logic built-in, from the docs:
The service proxy handles all failover exceptions for the service
partition it is created for. It re-resolves the endpoints if there are
failover exceptions (non-transient exceptions) and retries the call
with the correct endpoint. The number of retries for failover
exceptions is indefinite. If transient exceptions occur, the proxy
retries the call.
With that said, you should not require to add extra retry logic, maybe you should try adjust the OperationRetrySettings for a better handling of these retries.
If does not solve the problem, and you still want to add the logic in your code, the simplest way to handle it is using a transient-fault-handling library like Polly, something like below:
var policy = Policy
.Handle<FabricServiceNotFoundException>()
.WaitAndRetry(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
});
policy.Execute(() => DoSomething());
In this sample, you do an exponential backoff between retries, if the number of calls is too big, I would recomend implement the circuit breaker approach instead.

Related

Autofac DependencyResolutionException

I am getting following error:
Autofac.Core.DependencyResolutionException: An exception was thrown while invoking the constructor 'Void .ctor(System.String, Int32)' on type 'AerospikeClient'.
Following is the stacktrace of autofac:
at Autofac.Core.Activators.Reflection.BoundConstructor.Instantiate()
at
Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext
context, IEnumerable1 parameters) at Autofac.Core.Activators.Reflection.ReflectionActivator.<ConfigurePipeline>b__11_0(ResolveRequestContext ctxt, Action1 next) at
Autofac.Core.Resolving.Middleware.DelegateMiddleware.Execute(ResolveRequestContext
context, Action1 next) at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt) at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action1 next) at
Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.b__1(ResolveRequestContext
ctxt) at
Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
context, Action1 next) --- End of inner exception stack trace --- at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action1 next) at
Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.b__1(ResolveRequestContext
ctxt) at
Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext
ctxt) at
Autofac.Core.Resolving.Middleware.RegistrationPipelineInvokeMiddleware.Execute(ResolveRequestContext
context, Action1 next) at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt) at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action1 next) at
Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.b__1(ResolveRequestContext
ctxt) at
Autofac.Core.Resolving.Middleware.ScopeSelectionMiddleware.Execute(ResolveRequestContext
context, Action1 next) at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt) at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action1 next) at
Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.b__1(ResolveRequestContext
ctxt) at
Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext
ctxt) at
Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope
currentOperationScope, ResolveRequest request) at
Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest
request) at
Autofac.Core.Resolving.ResolveOperation.Execute(ResolveRequest
request) at
Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(ResolveRequest
request) at
Autofac.ResolutionExtensions.TryResolveService(IComponentContext
context, Service service, IEnumerable1 parameters, Object& instance) at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable1 parameters) at
Autofac.ResolutionExtensions.ResolveOptional(IComponentContext
context, Type serviceType, IEnumerable`1 parameters) at
Autofac.ResolutionExtensions.ResolveOptional(IComponentContext
context, Type serviceType) at
Autofac.Extensions.DependencyInjection.AutofacServiceProvider.GetService(Type
serviceType) at
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider
sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
Following is my registration:
builder.RegisterType<AerospikeClient>().As<IAerospikeClient>()
.WithParameter("hostname", _configuration["AerospikeHostName"])
.WithParameter("port", int.Parse(_configuration["AerospikePort"]))
.SingleInstance();
_configuration is getting passed to my autofac module and it is of type IConfigurationRoot. I am doing this so that I can pass values from outside.
If I change the above registration to:
builder.RegisterType<AerospikeClient>().As<IAerospikeClient>()
.WithParameter("hostname", "172.27.159.44")
.WithParameter("port", 3000)
.SingleInstance();
then it starts working. However I don't want to hardcode my values like that. Then I lose my chance of overriding them based on different environments.
What am I doing wrong here?
Check the actual type returned from _configuration["AerospikeHostName"]. Is it actually string, or is it something that happens to be assignable to string?
Equally, check the actual value used is valid, because Autofac should be fine expecting that string value.
Also, in future, consider using the built-in diagnostics to get a clearer picture of what exceptions are being thrown during resolve operations.

.NET Core issue: System.OperationCanceledException when hosted in IIS

My program.cs file in .NET Core 3.1 is like this I am creating web API in .net core but I am getting this error when hosted on server in IIS. API is working fine when hosted locally.
public class Program
{
public static void Main(string[] args)
{
var logger = NLogBuilder.ConfigureNLog(String.Concat(Directory.GetCurrentDirectory(), "/nlog.config")).GetLogger();
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}).ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
})
.UseNLog();
}
System.OperationCanceledException: at program.cs error
I am getting this error with stack trace like:
Description: The process was terminated due to an unhandled exception.
Exception Info: System.OperationCanceledException: The operation was canceled.
at System.Threading.CancellationToken.ThrowOperationCanceledException()
at System.Threading.CancellationToken.ThrowIfCancellationRequested()
at Microsoft.Extensions.Hosting.Internal.Host.StopAsync(CancellationToken
cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.WaitForShutdownAsync(IHost
host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost
host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost
host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost
host)
What is wrong here?
I am experiencing the same error, and I was trying to see what might cause it.
I came across this link with the same issue
and the thing that jumped out at me was the "non-graceful shutdown". To test, I recycled the application website on IIS, which did not trigger the error. I then tried turning off the app pool via IIS, and DID trigger the exception.
This leads me to believe it has something to do with a task running inside the application that is cut short when the non-graceful shutdown occurs.
In my case, I have a HostedService running in the background of my application, do you have something similar in yours?

Complete task in Action without awaiting - task gets cancelled

I have an async action, that completes a task that i need to wait for, before returning response to the cliend, but also a task that a want to run, but i don't care about the result.
[HttpPost]
[Route("api/update")]
public async Task Update(Competence competence)
{
await _competenceService.Update(competence);
_userService.DoNotWaitForMe(competence.Year);
}
Both _competenceService and _userService classes are injected into controller as Scoped via DI and both its methods are awaitable. I also use Entity framework and inject context class
// Startup.cs
services.AddScoped<ICompetenceService, CompetenceService>();
services.AddScoped<IUserService, UserService>();
services.AddDbContext<DbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DbContext"));
});
// CompetenceService.cs
async Task Update(Competence competence)
// UserService.cs
async Task DoNotWaitForMe(int Year)
While the awaited Update method completes as expected (or throws Exception on exception), the later never finishes, and throws exception
System.Threading.Tasks.TaskCanceledException: A task was canceled. at
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean
errorsExpected, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean
errorsExpected, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken
cancellationToken, Boolean errorsExpected) at
Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject
parameterObject, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.AsyncQueryingEnumerable1.AsyncEnumerator.MoveNextAsync()
at
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1
source, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1
source, CancellationToken cancellationToken)
and sometimes also
System.ObjectDisposedException: Cannot access a disposed object. A
common cause of this error is disposing a context that was resolved
from dependency injection and then later trying to use the same
context instance elsewhere in your application. This may occur if you
are calling Dispose() on the context, or wrapping the context in a
using statement. If you are using dependency injection, you should
let the dependency injection container take care of disposing context
instances.
I would like to prevent DI (or whatever is responsible) from cancelling the Task, and disposing all the objects untill this async task is completed. Is there any way?
Simply, you can't just not await the task. The EF context has a scoped lifetime: it's instantiated when the request starts and disposed when the request finishes. If you return the response, before the work being done on the context is finished, then the context will be disposed, and an ObjectDisposedException will be thrown.
It's pretty much always wrong to not await tasks, especially in a web app. It is not the same as backgrounding. If you want to do something in the background, then you need to schedule it on an actual background service. That could be anything really: a separate process, a console app, an Azure Function, or a hosted service. The long and short is that you need to do the work on something actually intended to process tasks in the background, not just fire-and-forget a task.

.NET Core SignalR 3.0 Exception

NOTE: This is SignalR for .NET Core 3.
I saw a couple of other stackoverflow suggestions (similar but not exact) for the applicationUrl modification which I have tried. I am getting:
Unhandled exception. System.InvalidOperationException: A path base can only be configured using IApplicationBuilder.UsePathBase().
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.ParseAddress(String address, Boolean& https)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IServerAddressesFeature addresses, KestrelServerOptions serverOptions, ILogger logger, Func2 createBinding)
at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.StartAsync[TContext](IHttpApplication1 application, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Hosting.WebHost.StartAsync(CancellationToken cancellationToken)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token, String startupMessage)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token, String startupMessage)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.Run(IWebHost host)
at cRioSaturnSignalRHub.Program.RunDefaultWebHostBuilder(String[] args, IConfigurationRoot config) in C:\Workspace\software\DataTier\dotNetCore\v3.x\Daemons\cRioSaturnSignalRHub\cRioSaturnSignalRHub\Program.cs:line 83
at cRioSaturnSignalRHub.Program.RunProcess(String[] args) in C:\Workspace\software\DataTier\dotNetCore\v3.x\Daemons\cRioSaturnSignalRHub\cRioSaturnSignalRHub\Program.cs:line 50
at cRioSaturnSignalRHub.Program.Main(String[] args) in C:\Workspace\software\DataTier\dotNetCore\v3.x\Daemons\cRioSaturnSignalRHub\cRioSaturnSignalRHub\Program.cs:line 27
The launch settings have applicationUrl = "http://localhost:5000" & the endpoint name is not on it as suggested in other stackoverflow related issue.
Any suggestions?
The problem is not at all related to the applicationUrl. Instead I tried the EnvironmentalVariables approach with the ASPNETCORE_URLS="http://*:5000" To do this I added .AddEnvironmentVariables() with the ConfigurationBuilder. & with WebHost.CreateDefaultBuilder(), I added .UseConfiguration(config). After this little change everything works when I publish & run.

How to Solve Redis Multiplexer in ASP.NET Core Problem

I my dotnet core project i am using redis for caching. In work fine in local,but i am getting following error in ubuntu server
Error
StackExchange.Redis.RedisConnectionException: It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. SocketClosed on PING
at StackExchange.Redis.ConnectionMultiplexer.ConnectAsync(String configuration, TextWriter log) in c:\code\StackExchange.Redis\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs:line 799
at Microsoft.Extensions.Caching.Redis.RedisCache.ConnectAsync(CancellationToken token)
at Microsoft.Extensions.Caching.Redis.RedisCache.GetAndRefreshAsync(String key, Boolean getData, CancellationToken token)
at Microsoft.Extensions.Caching.Redis.RedisCache.RefreshAsync(String key, CancellationToken token)
at Microsoft.AspNetCore.Session.DistributedSession.CommitAsync(CancellationToken cancellationToken)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
Unhandled Exception: StackExchange.Redis.RedisConnectionException: It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. SocketClosed on PING
at StackExchange.Redis.ConnectionMultiplexer.ConnectAsync(String configuration, TextWriter log) in c:\code\StackExchange.Redis\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs:line 799
at Microsoft.Extensions.Caching.Redis.RedisCache.ConnectAsync(CancellationToken token)
at Microsoft.Extensions.Caching.Redis.RedisCache.SetAsync(String key, Byte[] value, DistributedCacheEntryOptions options, CancellationToken token)
at otpservice.Helper.HOtp.GenerateOtp(String userid) in D:\SampleHelper\HOtp.cs:line 39
at otpservice.Controllers.OtpController.Otp(Object userData) in D:\Sample\Controllers\OtpController.cs:line 41
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Threading.ThreadPoolWorkQueue.Dispatch()
Aborted
ConfigureService method in Startup.cs
services.AddDistributedRedisCache(options =>
{
options.InstanceName = "Sample";
//For the Server i am using IP Instead of localhost
options.Configuration = "localhost";
});
During caching in my Code
var cache = new RedisCache(new RedisCacheOptions
{
//For the Server i am using IP Instead of localhost
Configuration = "localhost",
});
How to Solve the error.
Thank you...