Non viene generata alcuna eccezione all'apertura di MySqlConnection?


14

Ho appena iniziato con asincrono e Task e il mio codice ha smesso di elaborare. Succede quando ho un pacchetto di rete in arrivo e provo a comunicare con il database all'interno del gestore pacchetti.

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

Il metodo Handle viene chiamato da un'attività asincrona

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

Ecco il metodo che penso stia causando il 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);
}

Metodo GetConnection di DatabaseProvider:

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

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

Costruttore di DatabaseConnection:

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

    _connection = connection;    
    _command = command;

    _connection.Open();
}

Quando commento questa riga, raggiunge il Console.WriteLine

_connection.Open();

3
Tieni presente che MySQL Connector / NET di Oracle (aka MySql.Data) non implementa effettivamente alcuna operazione asincrona: stackoverflow.com/a/40065501/23633 Se desideri utilizzare operazioni asincrone con MySQL, dovresti passare a nuget.org/ pacchetti / MySqlConnector
Bradley Grainger

Sembra che tu abbia un deadlock nel tuo codice. Consiglierei di entrare nel debugger di Visual Studio quando ciò accade e di aprire la finestra Stack parallele. Se questo mostra uno o più thread con stack di chiamate che si bloccano su un'attività (o qualche primitiva di sincronizzazione), si spera che sarai in grado di dire cosa non va (o modificare ulteriori dettagli nella domanda per aiutarci). Se nessuno dei thread è bloccato su un'attività, probabilmente hai un'attività che non viene mai completata e che non attiva mai il codice awaitin essa contenuto. È molto più difficile da diagnosticare.
Bradley Grainger

È possibile aggiungere l'implementazione di DatabaseConnection.DisposeAsync?
eisenpony,

Se aspetti 5 minuti, alla fine genera un'eccezione? Connection.opennon ritorna mentre sta tentando di connettersi, ma alla fine si arrenderà dopo un timeout impostato. In alternativa, è possibile modificare il valore di timeout sull'oggetto di connessione su un numero inferiore maggiore di 0 e vedere se esiste un'eccezione.
weichch

Risposte:


1

Ho eseguito un progetto POC eseguendo 100 attività parallele sia con MySql.Data 8.0.19 che con MySqlConnector 0.63.2 sull'applicazione console .NET Core 3.1. Creo, apro e dispongo la connessione nel contesto di ogni singola attività. Entrambi i provider funzionano fino al completamento senza errori.

Le specifiche sono che le query MySql.Data vengono eseguite in modo sincrono sebbene la libreria fornisca la firma dei metodi asincroni, ad esempio ExecuteReaderAsync () o ExecuteScalarAsync (), mentre MySqlConnector funziona in modo veramente asincrono .

Potresti imbatterti in:

  • una situazione di deadlock non specificamente correlata al provider mysql
  • non gestire correttamente le eccezioni all'interno delle attività (è possibile controllare l'eccezione aggregata associata all'attività e monitorare anche i log db mysql)
  • l'esecuzione verrà comunque bloccata (non restituendo il risultato) quando si presume che non funzioni, se si esegue un numero elevato di attività parallele con MySql.Data mentre viene eseguita in modo sincrono

0

Il multi-threading con MySQL deve utilizzare connessioni indipendenti. Detto questo, il multithreading non è una domanda MySQL ma un problema per il linguaggio client, C # nella tua domanda.

Cioè, costruisci i tuoi thread senza riguardo a MySQL, quindi crea una connessione in ogni thread che deve eseguire query. Sarà sulle tue spalle se devi passare i dati tra i thread.

Di solito trovo che l'ottimizzazione delle query elimini la tentazione di multi-thread delle mie applicazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.