rebus-org / Rebus.SqlServer

:bus: Microsoft SQL Server transport and persistence for Rebus
https://mookid.dk/category/rebus
Other
43 stars 42 forks source link

Conflicting behaviour and hangs with Entity Framework Core SqlServer #21

Closed bzuu closed 5 years ago

bzuu commented 6 years ago

I am seeing very strange behaviour when using Rebus.SqlServer in a very specific combination with Entity Framework Core. As soon as I just add the Entity Framework Core SqlServer NuGet package and not even use it anywhere in my code I am seeing a continuous stream of thread exited messages in the Visual Studio Output window when debugging:

The thread 0x3be6 has exited with code 0 (0x0).
The thread 15335 has exited with code 0 (0x0).
The thread 0x3be7 has exited with code 0 (0x0).
The thread 15337 has exited with code 0 (0x0).
etc.

After a while the application just hangs completely, probably related to the above.

A couple of observations I made so far:

I have created a minimal reproduction model and uploaded it here.

Just open the solution in Visual Studio and hit F5 to see the behaviour. Note that the solution by default uses Docker to run.

mookid8000 commented 6 years ago

That sounds very weird....... I have another bug report though in relation to SQL Server and Docker stuff, so your reproduction is most welcome 🤘

mookid8000 commented 6 years ago

Sorry, but I am a Docker n00b.... I can understand that Docker Compose is used to start a Linux container with SQL Server alongside the container hosting the app, but how are the two connected?

As in: How does the host address 127.0.0.1,5433 from the connection string get mapped to the SQL Server instance running in the other container?

The reason I am asking is because I get this error when I press F5 on the docker-compose project

Rebus.Injection.ResolutionException occurred
  HResult=0x80131500
  Message=Could not resolve Rebus.Transport.ITransport with decorator depth 0 - registrations: Rebus.Injection.Injectionist+Handler
  Source=<Cannot evaluate the exception source>
  StackTrace:
   at Rebus.Injection.Injectionist.ResolutionContext.Get[TService]()
   at Rebus.Config.RebusConfigurer.<>c.<Start>b__12_11(IResolutionContext c)
   at Rebus.Injection.Injectionist.ResolutionContext.Get[TService]()
   at Rebus.Config.RebusConfigurer.<Start>b__12_22(IResolutionContext c)
   at Rebus.Injection.Injectionist.ResolutionContext.Get[TService]()
   at Rebus.Config.RebusConfigurer.<>c__DisplayClass12_1.<Start>b__23(IResolutionContext c)
   at Rebus.Injection.Injectionist.ResolutionContext.Get[TService]()
   at Rebus.Injection.Injectionist.Get[TService]()
   at Rebus.Config.RebusConfigurer.Start()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitSingleton(SingletonCallSite singletonCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass22_0.<RealizeService>b__0(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ApplicationBuilderExtensions.UseRebus(IApplicationBuilder app)
   at WebApplication5.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env) in C:\temp\rebus-ef-conflict\WebApplication5\Startup.cs:line 44
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app)
   at Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder builder)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at WebApplication5.Program.BuildWebHost(String[] args) in C:\temp\rebus-ef-conflict\WebApplication5\Program.cs:line 21
   at WebApplication5.Program.Main(String[] args) in C:\temp\rebus-ef-conflict\WebApplication5\Program.cs:line 17

Inner Exception 1:
AggregateException: One or more errors occurred. (A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught))

Inner Exception 2:
SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught)

Inner Exception 3:
AggregateException: One or more errors occurred. (No such device or address)

Inner Exception 4:
ExtendedSocketException: No such device or address

indicating that the connection could not be made....... any clues?

bzuu commented 6 years ago

Sorry for not being clear on that. Firstly I would guess that the behaviour you are seeing is due to SQL server not starting up in time before the application does. As the SQL server container keeps running after you stop debugging you most likely can work around this by simply trying to hit F5 again after the first attempt fails. This is just a buggy piece of example code on my end that does not properly handle the DB not yet being available at startup. Should perhaps have done some polling.

If that does not resolve the issue let me try to explain a bit about how the Docker setup works. In the docker-compose.yml file you can see there are two containers started: one named sqlserver and one named webapplication5. The detailed configuration for these can be found in docker-compose.override.yml. In this file the sqlserver container port 1433 is mapped onto the loopback address port 5433 of the host machine. What this means in practise is that when you access SQL server from within another container it is accessible under its docker name sqlserver on the regular port 1433. When however you are trying to access SQL from the host machine you use 127.0.0.1 on port 5433.

That being said you can see this reflected in there being two different connection strings defined. One in appsettings.json, which is picked up when you are not running in Docker. Then there is an environment variable defined in the docker-compose.override.yml file which is used when you run the application in Docker as the environment variable takes precedence over the configuration in the json file.

Finally it is important to realize that if you try to run the application without Docker it still relies on the SQL server instance that does run in Docker. You can simply get it to run by first running the whole thing in Docker once, which triggers the SQL container to be started.

Hope this makes sort of sense, if not let me know.

mookid8000 commented 5 years ago

hi @bzuu , I'm sorry for not coming back to this one for so long.... I guess I assumed you would make some noise if it was still a problem..... any news on this? Is it still a problem?

mookid8000 commented 5 years ago

Hi @bzuu , I'm closing this one for now. Please feel free to come back if you didn't figure it out.