Не возникает ли исключение при открытии MySqlConnection?

14

Я только начинаю с async и Task, и мой код перестал обрабатываться. Это происходит, когда у меня есть входящий сетевой пакет, и я пытаюсь связаться с базой данных внутри обработчика пакетов.

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

Метод Handle вызывается из асинхронной задачи

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

Вот метод, который, я думаю, вызывает проблему

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

Метод GetConnection для DatabaseProvider:

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

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

Конструктор DatabaseConnection:

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

    _connection = connection;    
    _command = command;

    _connection.Open();
}

Когда я закомментирую эту строку, она достигает Console.WriteLine

_connection.Open();
AAA
источник
3
Имейте в виду, что Oracle MySQL Connector / NET (он же MySql.Data) на самом деле не реализует никаких асинхронных операций: stackoverflow.com/a/40065501/23633 Если вы хотите использовать асинхронные операции с MySQL, вам следует переключиться на nuget.org/ пакеты / MySqlConnector
Брэдли Грейнджер
Похоже, у вас тупик в вашем коде. Я бы порекомендовал взломать отладчик Visual Studio, когда это произойдет, и открыть окно Parallel Stacks. Если это показывает один или несколько потоков со стеками вызовов, которые блокируют задачу (или некоторый примитив синхронизации), то вы, надеюсь, сможете сказать, что происходит не так (или отредактировать более подробную информацию в вопросе, чтобы помочь нам). Если ни один из потоков не заблокирован в Задаче, то у вас, вероятно, есть Задача, которая никогда не завершается, и никогда не активируете код, awaitсодержащийся в ней. Это гораздо сложнее диагностировать.
Брэдли Грейнджер
Можете ли вы добавить реализацию DatabaseConnection.DisposeAsync?
eisenpony
Если вы ждете, скажем, 5 минут, это в конечном итоге выдает исключение? Connection.openне возвращается, когда пытается подключиться, но, наконец, сдается после установленного времени ожидания. Или вы можете изменить значение времени ожидания для объекта подключения на меньшее число, большее 0, и посмотреть, есть ли исключение.
Weichch

Ответы:

1

Я запустил проект POC, включив в себя 100 параллельных задач с MySql.Data 8.0.19 и MySqlConnector 0.63.2 в консольном приложении .NET Core 3.1. Я создаю, открываю и размещаю соединение в контексте каждой отдельной задачи. Оба провайдера работает до завершения без ошибок.

Специфика заключается в том, что запросы MySql.Data выполняются синхронно, хотя библиотека предоставляет подпись асинхронных методов, например, ExecuteReaderAsync () или ExecuteScalarAsync (), тогда как MySqlConnector выполняется действительно асинхронно .

Вы можете столкнуться с:

  • тупиковая ситуация, не связанная напрямую с провайдером mysql
  • неправильная обработка исключений внутри ваших задач (вы можете проверять связанные с задачей агрегатные исключения, а также отслеживать журналы mysql db)
  • ваше выполнение будет по-прежнему заблокировано (не возвращая результат), если вы предполагаете, что оно не работает, если вы выполняете большое количество параллельных задач с MySql.Data, поскольку он выполняется синхронно
kalitsov
источник
0

Многопоточность с MySQL должна использовать независимые соединения. Учитывая это, многопоточность - это не вопрос MySQL, а проблема клиентского языка, C # в вашем вопросе.

То есть создавайте свои потоки без учета MySQL, а затем создайте соединение в каждом потоке, который должен выполнять запросы. Это будет на ваших плечах, если вам нужно будет передавать данные между потоками.

Я обычно нахожу, что оптимизация запросов устраняет соблазн многопоточности моих приложений.

Рик Джеймс
источник