Manage periodic tasks with QNetworkAccessManager



  • I've a periodic task that run each day that send HTTP requests. I create a thread for those tasks but after some days it crashes at reply = networkaccessmanager.get(). Maybe it crashes due to creating a NAM each day for each thread. It is possible that creating more NAM will crash the app?
    Btw I tried to use one single NAM but it fails to generate a reply due to "Thread parent error" (create a reply in a different thread wich NAM was created) .
    I made this due to send HTTP request in parallel, but now I'm reading that NAM will execute 6 parallel request (for desktop).
    So what is the best practice for manage this scenario?
    I'm thinking to create a Singleton NAM and each thread send signal to it for sending requests, but how can I connect reply back to the correct thread?


  • Qt Champions 2018

    @TheEnigmist

    Do you really need to have the NAM in threads?

    The longest time should be getting the data from network, and thanks to Signals&Slots that should not block your program.

    You can then emit the data to different threads for processing, if needed. But maybe that processing don't need multiple threads too?

    Regards



  • @aha_1980 said in Manage periodic tasks with QNetworkAccessManager:

    @TheEnigmist

    Do you really need to have the NAM in threads?

    The longest time should be getting the data from network, and thanks to Signals&Slots that should not block your program.

    You can then emit the data to different threads for processing, if needed. But maybe that processing don't need multiple threads too?

    Regards

    Not really. I'm editing my project so I'll use only 1 NAM for entire program. But I'm facing a problem I don't know how to solve.
    I created my NAM with 1 signal and 1 slot like this:

    SIGNAL

    void finished(Status, const QString &);
    

    SLOT (I don't really know if I need it to be a slot or a normal method)

    sendRequest(const QNetworkRequest & request, Method method, const QByteArray & data) {
    	QNetworkReply *reply;
    
    	switch (method) {
    		case Network::GET:
    			reply = nam->get(request);
    			break;
    		case Network::POST:
    			reply = nam->post(request, data);
    			break;
    		default:
    			reply = nam->get(request);
    			break;
    	}
    
    	connect(reply, &QNetworkReply::finished, [this, reply] () {
    		if (reply->error())
    			emit finished(Network::ERROR, QString("%1 %2").arg(QString::number(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()), reply->errorString()));
    		else
    			emit finished(Network::OK, QString(reply->readAll()));
    		reply->deleteLater();
    	});
    }
    

    Now, when I use it, I connect finished signal to thread I need, but, as expected, the response will be caught from all threads and not only by the one I need.

    connect(network, &Network::finished, [=] (Network::Status status, const QString & reply) {
       //Thread specific behaviour
    }
    

    There is a way to disconnect this connection after it reach the lambda his end?

    EDIT
    Maybe I found a solution, I added this line at the end of lambda function:

    disconnect(network, &Network::finished, 0, 0);
    

    I disconnect everything connected to Network so I'm sure each request will trigger 1 finished connection

    Is it a good solution or can I improve it?


  • Lifetime Qt Champion

    Hi,

    @TheEnigmist said in Manage periodic tasks with QNetworkAccessManager:

    Now, when I use it, I connect finished signal to thread I need, but, as expected, the response will be caught from all threads and not only by the one I need.

    What exactly do you mean by that ? It is not clear based on your current code snippet.



  • @SGaist said in Manage periodic tasks with QNetworkAccessManager:

    Hi,

    @TheEnigmist said in Manage periodic tasks with QNetworkAccessManager:

    Now, when I use it, I connect finished signal to thread I need, but, as expected, the response will be caught from all threads and not only by the one I need.

    What exactly do you mean by that ? It is not clear based on your current code snippet.

    Sorry, I try to be more clear.
    I use it for all my HTTP requests, and I use connect even if it will be a one time request. After the response the connection is still alive and if I forget to disconnect it, when Network emits finished it trigger that connection again, so I solved it with:

    disconnect(network, &Network::finished, 0, 0);
    

    And I'm asking if it is good or there is a better way to manage single NetworkAccessManager.

    EDIT:

    1. Another question is for multiple requests, f.e. if I send a HTTP request and then based on response I need to send another request, do I have to use connect() inside first connect()? Something like this:
    network->sendRequest(firstRequest, Network::GET);
    connect(network, &Network::finished, [=] (Network::Status status, const QString & reply) {
          disconnect(network, &Network::finished, 0, 0); //prevent triggering again
          /*
          parse reply
         */
         network->sendRequest(secondRequest, Network::GET);
         connect(network, &Network::finished, [=] (Network::Status status, const QString & reply) {
                  disconnect(network, &Network::finished, 0, 0); //prevent triggering again
          }
    
    1. When I use that Network class with parallel threads they get response from all other threads, how can I get the correct response for each thread? Actually I've connected them like this:
    connect(this, &ThreadWorker::sendRequest, network, &Network::sendRequest);
    connect(network, &Network::finished, this, &ThreadWorker::response); // <- this will output the same response (I suppose first) instead of expected thread  specific response
    

  • Lifetime Qt Champion

    Would it be possible to look at the complete implementation ?

    From your snippet, it is not really clear.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.