2

I have a .Net Core 3.1 WebAPI running as a Docker container + Eureka server running as Docker also. When I run the API from Visual Studio it registers successfully with the Eureka Docker instance and I can see the service in Eureka console. But once I dockerize the API and run it I am getting connection error as below :

fail: Steeltoe.Discovery.Eureka.Transport.EurekaHttpClient[0]
productsapi_1   |       RegisterAsync Failed
productsapi_1   | System.Net.Http.HttpRequestException: Connection refused
productsapi_1   |  ---> System.Net.Sockets.SocketException (111): Connection refused
productsapi_1   |    at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
productsapi_1   |    --- End of inner exception stack trace ---
productsapi_1   |    at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
......
productsapi_1   |    at Steeltoe.Discovery.Eureka.Transport.EurekaHttpClient.RegisterAsync(InstanceInfo info)
productsapi_1   | fail: Steeltoe.Discovery.Eureka.DiscoveryClient[0]
productsapi_1   |       Register Failed
productsapi_1   | System.Net.Http.HttpRequestException: Connection refused
productsapi_1   |  ---> System.Net.Sockets.SocketException (111): Connection refused
productsapi_1   |    at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
productsapi_1   |    --- End of inner exception stack trace ---
productsapi_1   |    at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
.....
productsapi_1   |    at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
productsapi_1   |    at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean 
disposeCts)
productsapi_1   |    at Steeltoe.Discovery.Eureka.Transport.EurekaHttpClient.RegisterAsync(InstanceInfo info)
productsapi_1   |    at Steeltoe.Discovery.Eureka.DiscoveryClient.RegisterAsync()
productsapi_1   | info: Steeltoe.Discovery.Eureka.DiscoveryClient[0]
productsapi_1   |       Registartion fail. HeartBeat not start
productsapi_1   | fail: Steeltoe.Discovery.Eureka.Transport.EurekaHttpClient[0]
productsapi_1   |       DoGetApplicationsAsync Failed
productsapi_1   | System.Net.Http.HttpRequestException: Connection refused
productsapi_1   |  ---> System.Net.Sockets.SocketException (111): Connection refused
.....

This is after running docker-compose up.Eureaka and API containers are both up but the service does not seem to be registering. This is how my WebAPI looks like :

Startup.cs

 public void ConfigureServices(IServiceCollection services)
    {
        .....       
        services.AddDbContext<ApplicationDbContext>(o => o.UseMySql(Configuration.GetConnectionString("mysqlconnection")));
        services.AddDiscoveryClient(Configuration);
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {        
       .....
        app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
        app.UseDiscoveryClient();
    }

Docker compose

version: '3.4'
services:
  productsapi:
    build: .
    ports: 
      - "5050:5000"
    depends_on:
      - eurekaserver
   
  eurekaserver:
    image: steeltoeoss/eureka-server:latest
    ports:
      - '8761:8761'

Appsettings.json

     {
     ...
  "AllowedHosts": "*",
  ...
  "eureka": {
    "client": {
      "shouldRegisterWithEureka": true,
      "serviceUrl": "http://eurekaserver:8761/eureka",
      "ValidateCertificates": false
    },
    "instance": {
      "appName": "ProductService",
      "port": "5050",
      "hostName": "localhost"
    }
  }
}

What am I missing ?

Golide
  • 835
  • 3
  • 13
  • 36
  • change the hostName from `localhost` to `host.docker.internal` – frank_lee Jul 23 '21 at 10:34
  • info: Steeltoe.Discovery.Eureka.DiscoveryClient[0] productsapi_1 | Registartion fail. HeartBeat not start productsapi_1 | fail: Steeltoe.Discovery.Eureka.Transport.EurekaHttpClient[0] productsapi_1 | DoGetApplicationsAsync Failed productsapi_1 | System.Net.Http.HttpRequestException: Connection refused – Golide Jul 23 '21 at 11:55
  • Still getting same error – Golide Jul 23 '21 at 11:55
  • eurekaserver_1 | 2021-07-22 06:24:57.603 INFO 1 --- [ Thread-15] com.netflix.discovery.DiscoveryClient : Shutting down DiscoveryClient ... eurekaserver_1 | 2021-07-22 06:24:57.603 INFO 1 --- [ Thread-15] com.netflix.discovery.DiscoveryClient : Completed shut down of DiscoveryClient eurekaserver_1 | 2021-07-23 11:54:01.954 INFO 1 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing – Golide Jul 23 '21 at 12:00

2 Answers2

2

I think it's most likely that Eureka is not ready to receive requests yet and that is the cause of the connection refused errors. In my experience, it takes 7-15(ish) seconds for Eureka to start. Docker compose will start the containers in dependency order, but does not wait for a ready state on the first before starting the next. There are options to change the startup behavior, or your application can be built to handle transient failures of this nature.

Steeltoe is built to handle this type of failure and will try (every 30 seconds by default) to send a heartbeat to Eureka. If the first request fails (because Eureka isn't up yet), the next should succeed.

The error message you've shared (and the github issue you opened) indicate that you're using Steeltoe 2.1.1, which was released nearly 3 years ago (before .NET Core 3.1). I don't think this is likely to be the root cause of the issue, but I'd strongly recommend using a newer version.

Tim
  • 2,587
  • 13
  • 18
1

Finally got it working with this OSS tweak . My appsettings.json now looks like this:

 {
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "mysqlconnection": "server=mysqldata;port=3306;database=ProductsDB;userid=xxxx;password=xxxx;"
  },
  "PaymentsServiceUri": "http://PaymentService/api/payment",
  "spring": {
    "application": {
      "name": "ProductService"
    }
  },
  "eureka": {
    "client": {
      "shouldRegisterWithEureka": true,
      "serviceUrl": "http://eurekaserver:8761/eureka",
      "ValidateCertificates": false,
      "RegistryFetchIntervalSeconds": "15"
    },
    "instance": {
      "appName": "ProductService",
      "port": "5050",
      "hostName": "localhost",
      "LeaseRenewalIntervalInSeconds": "15"
    }
    }
  }
Golide
  • 835
  • 3
  • 13
  • 36
  • So, just to be clear - the real issue was that Eureka wasn't ready for connections and the app does eventually register successfully? The two key changes to appsettings being `Eureka:Client:RegistryFetchIntervalSeconds` and `Eureka:Instance:LeaseRenewalIntervalInSeconds`, resulting in faster retries – Tim Jul 29 '21 at 12:52
  • 1
    Yes those were the changes needed – Golide Jul 29 '21 at 13:22