npgsql: SocketException: A non-blocking socket operation could not be completed immediately [::1]:5432

I get a SocketException every time when opening a new database connection after upgrading from 3.05 to 3.1.4.

using (var conn = new NpgsqlConnection("Server=localhost;Port=5432;User Id=postgres;Password=password;Database=Db1;Pooling=True;Timeout=15;"))
{
        conn.Open(); //Exception happens here
}

A non-blocking socket operation could not be completed immediately [::1]:5432

The connection is successful but the exception is annoying as it makes Visual Studio break every time a new database connection is opened if “Break when thrown” is checked.

Can I do anything to prevent the exception to be thrown?

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 4
  • Comments: 18 (10 by maintainers)

Most upvoted comments

Npgsql 3.1.0 establishes a connection by putting the socket in non-blocking mode and then selecting on it - this the standard way to apply a connection timeout on a synchronous socket connection attempt. Unfortunately .NET exposes EWOULDBLOCK as an exception, although it’s not an actual error.

Long story short, there’s nothing really you can do except exclude SocketException from the “Break when thrown” list, that’s how I debug Npgsql.

I agree with you, and it’s true it was more about the migration process than using this on other place.

At the end, seems there is some workaround possible for this issue at starting the app. Maybe i should have searched more. For migration logic this can be a valid implementation workaround on an ASP.NET Core project, only by deffering the migration step before the web server launch. This is taken from Built in options for running async tasks article:

public class Program
{
    public static async Task Main(string[] args)
    {
        IWebHost webHost = CreateWebHostBuilder(args).Build();

        // Create a new scope
        using (var scope = webHost.Services.CreateScope())
        {
            // Get the DbContext instance
            var myDbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();

            //Do the migration asynchronously
            await myDbContext.Database.MigrateAsync();
        }

        // Run the WebHost, and start accepting requests
        // There's an async overload, so we may as well use it
        await webHost.RunAsync();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

Sorry for the inconvenience.

EDIT: Forgot to mention, the workaround is to deffer the database migration elsewhere and mainly making the Program.Main method async.

Sorry to comment here nearly 1 year after the last comment, but even if it may sound obvious, for future readers, if you have this issue at some point during your debugging experience, just change theses call in your synchronous context:

dbContext.Database.GetPendingMigrations().ToList();
dbContext.Database.Migrate();

To this instead:

dbContext.Database.GetPendingMigrationsAsync().GetAwaiter().GetResult().ToList();
dbContext.Database.MigrateAsync().GetAwaiter().GetResult();

This way the SocketException will not be thrown by default.

If you want to be cautious, you can try to do this only in DEBUG configuration / Development if any doubt.

Fair enough! I’ll look into this.

I disagree…instead of using socket.Connect, you should be using socket.BeginConnect, this will not throw an exception. See line 652 in https://github.com/npgsql/npgsql/blob/dev/src/Npgsql/NpgsqlConnector.cs

Instead of:

                try
                {
                    socket.Connect(endpoint);
                }
                catch (SocketException e)
                {
                    if (e.SocketErrorCode != SocketError.WouldBlock)
                        throw;

}

Something like: var asyncResult = socket.BeginConnect(addressList, portNumber, null, null); // Give it a reasonable amount of time to setup the connection asyncResult.AsyncWaitHandle.WaitOne(_receiveTimeout, false);