Nenhuma exceção sendo lançada ao abrir o MySqlConnection?

14

Estou apenas começando com async e Task e meu código parou de processar. Isso acontece quando tenho um pacote de rede recebido e tento me comunicar com o banco de dados dentro do manipulador de pacotes.

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");
    }
}

O método Handle é chamado de uma tarefa assíncrona

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

Aqui está o método que eu acho que está causando o 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 do DatabaseProvider:

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

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

Construtor DatabaseConnection:

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

    _connection = connection;    
    _command = command;

    _connection.Open();
}

Quando eu comento esta linha, ela atinge o Console.WriteLine

_connection.Open();
AAA
fonte
3
Esteja ciente de que o MySQL Connector / NET da Oracle (também conhecido como MySql.Data) não implementa nenhuma operação assíncrona: stackoverflow.com/a/40065501/23633 Se você quiser usar operações assíncronas com o MySQL, mude para nuget.org/ packages / MySqlConnector
Bradley Grainger
Parece que você tem um impasse no seu código. Eu recomendaria invadir o depurador do Visual Studio quando isso acontecer e abrir a janela Parallel Stacks. Se isso mostrar um ou mais threads com pilhas de chamadas bloqueadas em uma tarefa (ou alguma primitiva de sincronização), esperamos que você possa dizer o que está acontecendo de errado (ou editar mais detalhes na pergunta para nos ajudar). Se nenhum dos threads estiver bloqueado em uma tarefa, provavelmente você terá uma tarefa que nunca será concluída e nunca ativará o código que está awaitnele. Isso é muito mais difícil de diagnosticar.
Bradley Grainger
Você pode adicionar a implementação de DatabaseConnection.DisposeAsync?
eisenpony 18/04
Se você esperar por 5 minutos, isso gera uma exceção? Connection.opennão retorna enquanto está tentando se conectar, mas finalmente desiste após um tempo limite definido. Ou você pode alterar o valor do tempo limite no objeto de conexão para um número menor maior que 0 e ver se há exceção.
weichch 18/04

Respostas:

1

Executei um projeto POC girando 100 tarefas paralelas, tanto com o MySql.Data 8.0.19 como com o MySqlConnector 0.63.2 no aplicativo de console do .NET Core 3.1. Crio, abro e descarro a conexão no contexto de cada tarefa. Ambos os provedores são executados sem erros.

As especificidades são que as consultas MySql.Data são executadas de forma síncrona, embora a biblioteca forneça assinatura de métodos assíncronos, por exemplo, ExecuteReaderAsync () ou ExecuteScalarAsync (), enquanto o MySqlConnector é executado de maneira verdadeiramente assíncrona .

Você pode estar se deparando com:

  • uma situação de conflito não relacionada especificamente ao provedor mysql
  • não lidando adequadamente com exceções em suas tarefas (você pode inspecionar a exceção agregada associada à tarefa e também monitorar logs mysql db)
  • sua execução ainda está bloqueada (não retornando resultado) quando você assume que não está funcionando, se você estiver executando um número alto de tarefas paralelas com o MySql.Data enquanto ele é executado de forma síncrona
Kalitsov
fonte
0

Multi-threading com MySQL deve usar conexões independentes. Dado que, o multithreading não é uma questão do MySQL, mas um problema para a linguagem do cliente, C # na sua pergunta.

Ou seja, construa seus threads sem considerar o MySQL, então crie uma conexão em cada thread que precise fazer consultas. Ele estará em seus ombros se você precisar passar dados entre os threads.

Normalmente, acho que a otimização de consultas elimina a tentação de multi-thread de meus aplicativos.

Rick James
fonte