¿No se produce ninguna excepción al abrir MySqlConnection?

14

Estoy comenzando con async y Task y mi código ha dejado de procesarse. Sucede cuando tengo un paquete de red entrante y trato de comunicarme con la base de datos dentro del controlador de paquetes.

public class ClientConnectedPacket : IClientPacket
{
    private readonly EntityFactory _entityFactory;

    public ClientConnectedPacket(EntityFactory entityFactory)
    {
        _entityFactory= entityFactory;
    }

    public async Task Handle(NetworkClient client, ClientPacketReader reader)
    {
        client.Entity = await _entityFactory.CreateInstanceAsync( reader.GetValueByKey("unique_device_id"));

        // this Console.WriteLine never gets reached
        Console.WriteLine($"Client [{reader.GetValueByKey("unique_device_id")}] has connected");
    }
}

Se llama al método Handle desde una tarea asincrónica

if (_packetRepository.TryGetPacketByName(packetName, out var packet))
{
    await packet.Handle(this, new ClientPacketReader(packetName, packetData));
}
else
{
    Console.WriteLine("Unknown packet: " + packetName);
}

Aquí está el método que creo que está causando el problema.

public async Task<Entity> CreateInstanceAsync(string uniqueId)
{
    await using (var dbConnection = _databaseProvider.GetConnection())
    { 
        dbConnection.SetQuery("SELECT COUNT(NULL) FROM `entities` WHERE `unique_id` = @uniqueId");
        dbConnection.AddParameter("uniqueId", uniqueId);

        var row = await dbConnection.ExecuteRowAsync();

        if (row != null)
        {
            return new Entity(uniqueId, false);
        }
    }

    return new Entity(uniqueId,true);
}

Método GetConnection de DatabaseProvider:

public DatabaseConnection GetConnection()
{
    var connection = new MySqlConnection(_connectionString);
    var command = connection.CreateCommand();

    return new DatabaseConnection(_logFactory.GetLogger(), connection, command);
}

Constructor de DatabaseConnection:

public DatabaseConnection(ILogger logger, MySqlConnection connection, MySqlCommand command)
{
    _logger = logger;

    _connection = connection;    
    _command = command;

    _connection.Open();
}

Cuando comento esta línea, llega al Console.WriteLine

_connection.Open();
AAA
fuente
3
Tenga en cuenta que el Conector MySQL / NET de Oracle (también conocido como MySql.Data) en realidad no implementa ninguna operación asincrónica: stackoverflow.com/a/40065501/23633 Si desea utilizar operaciones asincrónicas con MySQL, debe cambiar a nuget.org/ paquetes / MySqlConnector
Bradley Grainger
Parece que tienes un punto muerto en tu código. Recomendaría entrar en el depurador de Visual Studio cuando esto suceda y abrir la ventana Pilas paralelas. Si esto muestra uno o más subprocesos con pilas de llamadas que se están bloqueando en una Tarea (o alguna primitiva de sincronización), entonces con suerte podrá decir qué está mal (o editar más detalles en la pregunta para ayudarnos). Si ninguno de los hilos está bloqueado en una Tarea, entonces es probable que tenga una Tarea que nunca se complete y que nunca active el código que está awaiten ella. Eso es mucho más difícil de diagnosticar.
Bradley Grainger
¿Se puede agregar la implementación de DatabaseConnection.DisposeAsync?
eisenpony
Si espera por unos 5 minutos, ¿finalmente arroja una excepción? Connection.openno regresa mientras intenta conectarse, pero finalmente se dará por vencido después de un tiempo de espera establecido. O podría cambiar el valor de tiempo de espera en el objeto de conexión a un número menor mayor que 0 y ver si hay una excepción.
Weichch

Respuestas:

1

Ejecuté un proyecto POC girando 100 tareas paralelas con MySql.Data 8.0.19 y MySqlConnector 0.63.2 en la aplicación de consola .NET Core 3.1. Creo, abro y dispongo la conexión en el contexto de cada tarea. Ambos proveedores se ejecutan hasta su finalización sin errores.

Los detalles son que las consultas MySql.Data se ejecutan sincrónicamente, aunque la biblioteca proporciona la firma de métodos asincrónicos, por ejemplo, ExecuteReaderAsync () o ExecuteScalarAsync (), mientras que MySqlConnector se ejecuta realmente de forma asincrónica .

Es posible que se encuentre con:

  • una situación de punto muerto no relacionada específicamente con el proveedor de mysql
  • no maneja adecuadamente las excepciones dentro de sus tareas (puede inspeccionar la excepción agregada asociada a la tarea y también monitorear los registros de mysql db)
  • su ejecución aún se bloquea (no devuelve el resultado) cuando asume que no está funcionando, si ejecuta una gran cantidad de tareas paralelas con MySql.Data mientras se ejecuta sincrónicamente
kalitsov
fuente
0

Los subprocesos múltiples con MySQL deben usar conexiones independientes. Dado que, el subprocesamiento múltiple no es una pregunta de MySQL sino un problema para el lenguaje del cliente, C # en su pregunta.

Es decir, construya sus hilos sin tener en cuenta MySQL, luego cree una conexión en cada hilo que necesite hacer consultas. Estará sobre sus hombros si necesita pasar datos entre los hilos.

Por lo general, encuentro que la optimización de consultas elimina la tentación de realizar múltiples subprocesos en mis aplicaciones.

Rick James
fuente