Taifunov
Taifunov

Reputation: 593

How to solve this:Web process failed to bind to $PORT within 60 seconds of launch heroku .NET Core 3.1 Console Application?

2020-11-11T15:57:56.534313+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch 2020-11-11T15:57:56.552989+00:00 heroku[web.1]: Stopping process with SIGKILL 2020-11-11T15:57:56.622618+00:00 heroku[web.1]:Process exited with status 137 2020-11-11T15:57:56.669934+00:00 heroku[web.1]: State changed from starting to crashed

After some minutes after deployment on heroku my .NET Core Console App i get this an error, how to solve it?

There is my Program.cs

internal class Program
    {
        private static async Task Main(string[] args)
        {
            var host = GetHost(args);
            await ConfigureVkAuth(host);
            host.Services.GetRequiredService<VkService>();
            host.Services.GetRequiredService<PostMessage>();
            host.Services.GetRequiredService<MyContext>();
            await host.RunAsync();
        }

        private static IHost GetHost(string[] args) =>
            new HostBuilder()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .ConfigureAppConfiguration(b => b.AddCommandLine(args))
                .ConfigureAppConfiguration((c, b) =>
                {
                    b.AddJsonFile("appsettings.json", true, true);
                })
                .ConfigureLogging(logging =>
                {
                    logging.ClearProviders();
                    logging.AddConsole();
                })
                .ConfigureServices((context, services) =>
                {
                    ConfigureMain(context, services);

                    ConfigureBot(services);

                    ConfigureVK(services);

                    services.InstallServicesInAssembly();
                })
                .Build();

        private static void ConfigureMain(HostBuilderContext context, IServiceCollection services)
        {
            services.Configure<DataOptions>(opts =>
                context.Configuration.GetSection(nameof(DataOptions)).Bind(opts));
            services.Configure<BotOptions>(opts =>
                context.Configuration.GetSection(nameof(BotOptions)).Bind(opts));
            services.Configure<ApiAuthParams>(opts =>
            {
                context.Configuration.GetSection(nameof(VkApiAuthParams)).Bind(opts);
                opts.Settings = Settings.All;
            });
        }

        private static void ConfigureBot(IServiceCollection services)
        {
            services.AddHttpClient<ITelegramBotClient, TelegramBotClient>()
                .AddTransientHttpErrorPolicy(builder =>
                    builder.WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(5d)));
            services.AddSingleton<ITelegramBotClient, TelegramBotClient>(provider =>
                new TelegramBotClient(provider.GetRequiredService<IOptions<BotOptions>>().Value.Token,
                    provider.GetRequiredService<IHttpClientFactory>().CreateClient(nameof(ITelegramBotClient))));
            services.TryAddTransient(s =>
                s.GetRequiredService<IHttpClientFactory>().CreateClient(string.Empty));
            services.AddTransient<PostPhoto>();
        }
        private static void ConfigureVK(IServiceCollection services)
        {
            services.AddSingleton<IVkApi, VkApi>(provider =>
                new VkApi(provider.GetRequiredService<ILogger<VkApi>>()));
            services.AddSingleton<VkService>();
            services.AddTransient<PostMessage>();
        }

        private static async Task ConfigureVkAuth(IHost host)
        {
            var vk = host.Services.GetRequiredService<IVkApi>();
            var credentials = host.Services.GetRequiredService<IOptions<ApiAuthParams>>().Value;
            await vk.AuthorizeAsync(credentials);
        }

Upvotes: 0

Views: 233

Answers (1)

taigadev
taigadev

Reputation: 59

Three steps helped me to resolve this problem:

  1. Create your startup.cs file with default minimal configuration:

Code sample:

public class Startup
{
    // startup with one main web page allows heroku to override listening port
    // otherwise heroku app goes down immediately

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "Default",
                pattern: "{controller=Home}/{action=Index}");
            endpoints.MapRazorPages();
        });
    }
}
  1. Create default controller. It could return 200ok response. (not sure if it needed for heroku, didnt test it yet)

Code sample:

public class HomeController : Controller
    {
        [HttpGet]
        public IActionResult Index()
        {
            return Ok();
        }
    }
  1. Bind your Startup to webHostDefaults and dont forget to UseKestrel with PORT environment variable:

Sample code:

...
private const string DefaultListenPort = "8080";

Host.CreateDefaultBuilder(args)
    .UseSerilog()
    .ConfigureWebHostDefaults(webBuilder =>
    {
         webBuilder.UseStartup<Startup>();
         webBuilder.UseKestrel(options =>
               options.ListenAnyIP(int.Parse(Environment.GetEnvironmentVariable("PORT") ??
                                                          DefaultListenPort)));
    })
    .ConfigureServices(...)

Upvotes: 0

Related Questions