Handling connection failures with IO::Socket::Async - asynchronous

I'm working on a small project using IO::Socket::Async. I'm trying write some tests to make sure I'm handling a connection loss properly but my initial attempts didn't go as planned. I thought using a QUIT phaser would work but that didn't give any response in the tests I tried closing the supply but that isn't giving the results I was hoping for. Can someone point me in the right direction on how to handle a connection loss with IO::Socket::Async?
An example of the supply where I try to use the quit is below. Since it isn't working how I expected. I am not sure if I am going about this correctly.
supply whenever $connection -> $event {
if $event ~~ /event message/ {
emit { status => $event };
}
QUIT {
.note;
say 'conection lost';
}
}

There are two ways a connection might be terminated:
EOF, which we consider an "orderly" close. The whenever subscription is much like a loop, and the LAST phaser triggers on orderly end of the stream. So, to handle this case, use LAST.
Erroneous termination, such as connection reset by peer, which will trigger the QUIT as you wrote (though you need QUIT { default { note $_ } } to actually handle it, just as with CATCH).
It seems that quite a few more cases are considered "orderly" (that is, the EOF case) than at least I expected. For example, run a server like this:
react {
whenever IO::Socket::Async.listen('localhost', 4242) -> $conn {
whenever $conn -> $stuff {
$conn.print($stuff);
}
}
}
And a client like this:
my $conn = await IO::Socket::Async.connect('localhost', 4242);
react {
whenever $conn -> $stuff {
say "Got back $stuff";
LAST {
say "Connection closed";
done;
}
QUIT {
default {
say "Connection lost: $_";
done;
}
}
}
whenever Supply.interval(1) {
$conn.print("hello $_\n");
}
}
Then Ctrl+C the server, and - at least on my local setup (Ubuntu in a VM) - it triggered the LAST. I wondered if this could be some kind of bug, so traced it all the way back into the VM's I/O binding, and no, we really are getting EOF passed to us from the operating system in that case, not an error. Sticking the server on a separate machine, and then disconnecting the wifi on my local one, was enough to trigger the QUIT case with a "Connection reset by peer".
In summary, QUIT is the right way to handle erroneous loss of connection, but LAST is triggered by EOF, and that shows up in some cases that we might consider "connection loss"; only the protocol being spoken atop of the socket can really determine whether this was an unexpected time for things to come to an end.

Related

kill a process without raising error with qt

I need to kill a process without raising any errors. I need to make distinction between when the process crashed and when the user killed it intentionally. I see that on Windows a command line process can be closed only using .kill() and not .terminate().
If I connect the .errorOccurred(), the function is called even if I intentionally press the button to kill the process. Is there a way to avoid this?
There is QObject::blockSignals(), which temporarily prevents any signal from being emitted.
However, I would avoid using it, and handle it instead in the code that is handling the process.
Two options:
Disconnect the process’ signals before terminating:
m_process.disconnect(this);
m_process.kill();
Remember that you’re in “killing state” and ignore the signal/handle it differently:
m_killingProcess = true; // member variable defaulting to false
m_process.kill();
In the slot connected to errorOccurred:
void Foo::processErrorOccurred(QProcess::ProcessError error)
{
if (m_killingProcess) {
// do nothing?
return;
}
// handle process error (when not killing)
}

How to Retry RxAndroidBLE Discover Services in case of GATT error.

I am using RxAndroidBLE library for discovering services in my GATT server.
it works fine most of the time but often i get GATT error 133 (0x85) and it fails. I will like to retry for discovery of the service couple of time for a time period, say for 5 seconds.
here is the code i am trying
bleDevice = mBleClient.getBleDevice(macAddress);
subscription = bleDevice.establishConnection(false)
.flatMap(RxBleConnection::discoverServices)
.first() // Disconnect automatically after discovery
.observeOn(AndroidSchedulers.mainThread())
.doOnUnsubscribe(this::onUnsubscribe)
.compose(this.bindToLifecycle())
.retryWhen(errors -> errors.flatMap(error -> {
if (isGattError(error) {
return Observable.just(new Object());
} else {
return Observable.error(error);
}
}
))
.timeout(5, TimeUnit.SECONDS)
.subscribe(this::getScanResult, this::onConnectionFailure);
Its not working and looks like the retryWhen is not getting called. It may be more of rxJava issue but i will really appreciate any help on this.
As you wrote in the comments your this::onUnsubscribe is calling subscription.unsubscribe() so the .retryWhen() operator has no possibility of being called.
You could move the .doOnUnsubscribe() below of .retryWhen() or the other way around to give get the intended behaviour.

meteor: how to stop asynchronous call?

Is it possible to stop (kill) asynchronous Call?
In my app I have at client side sth like:
Meteor.call('doCalculation', function(err, result) {
//do sth with result
});
'doCalculation' may take long time (this is ok) I dont want user to start new call when he/she has already one running call, I want to allow user to stop current call and submit new one. How correctly do this?
The only idea I have is to communicate between client and server using mongo. In some place in 'doCalculation' function I can observe some mongo document/collection and based on this do sth in the function (e.g. call exception). Do you have any better ideas?
You can use a semaphore for this purpose. When the semaphore is 1, requests are allowed to be sent. When the semaphore is 0, requests are not allowed to be sent. The semaphore should be 1 by default and just before you send the request, you need to set it to 0. When a response is successful, you set the semaphore back to 1.
As about the timeout: You could use a time out using setTimeout after sending the request, like this:
if (semaphore) {
var isTimedOut = false;
var isSuccess = false;
semaphore = 0; //No need to use var keyword, as this should be declared outside of this scope
Meteor.call('doCalculation', function(err, result) {
isSuccess = true;
//do sth with result
});
setTimeout(function() {
if (!isSuccess) {
isTimeout = true;
//do something else, to handle the time out state
}
}, 10000);
}
This is tricky, because you cannot generally set timeouts from the client's point of view. You don't need to, for a bunch of architectural reasons. The most important thing is that if you lose network connectivity or the server crashes (two cases timeouts are designed to manage), the client is aware immediately because it is disconnected. You can use Meteor.status().connected if this happens often.
It sounds like you're running a long calculation on the server. My suggestion is to return a calculationId immediately, and then update a collection with progress, e.g., CalculationProgresses.update(calculationId, {$set: {progress: currentProgress}}) as you calculate. Your UI can then update the progress reactively, in the most convenient way possible.
Note, that when you do run long calculations on the server, you need to occasionally "yield," giving the chance for other work to happen. Node, on which Meteor is based, is tricky for long calculations if you don't master this notion of yielding. In Meteor, you can yield easily by updating a collection (e.g., your progress collection). This will solve lots of problems you're probably experiencing as you write your application.
i think you need a server-side solution for this. if you go with a client-side solution, you don't handle 2 cases:
the user reloads their browser
the user uses 2 browsers
i would create these methods:
isCalculationActive() -- this checks if the user already has a calculation active. on the server, you can either keep that fact in memory or write it to the db. on the client, if this returns false, then you can proceed to call doCalculation(). if true, you can give the user a popup or alert or something to ask if they want to cancel and proceed.
doCalculation() -- this cancels any outstanding calculation by that user and starts a new one.
with these implemented, the user can reload their browser w/o affecting either the running calculation or correct behavior. and if they try a 2nd browser, everything should still work as expected.
if you want to give the user the option to simply stop the job and not start a new one, then you can simply create:
cancelCalculation() -- this cancels any outstanding calculation by that user.

Why does meteor undo changes to collections nested in an observer method?

I am trying to implement something like this:
/* We use the command pattern to encode actions in
a 'command' object. This allows us to keep an audit trail
and is required to support 'undo' in the client app. */
CommandQueue.insert(command);
/* Queuing a command should trigger its execution. We use
an observer for this. */
CommandQueue
.find({...})
.observe({
added: function(command) {
/* While executing the action encoded by 'command'
we usually want to insert objects into other collections. */
OtherCollection.insert(...)
}
});
Unfortunately it seems that meteor keeps the prior state of the OtherCollection while executing the transaction on CommandQueue. Changes are made temporarily to the OtherCollection. As soon as the transaction on CommandQueue finishes, the prior state of the OtherCollection will be restored, though, and our changes disappear.
Any ideas why this is happening? Is this intended behaviour or a bug?
This is the expected behavior, though it is a little subtle, and not guaranteed (just an implementation detail).
The callback to observe fires immediately when the command is inserted into CommandQueue. So the insert to OtherCollection happens while the CommandQueue.insert method is running, as part of the same call stack. This means the OtherCollection insert is considered part of the local 'simulation' of the CommandQueue insert, and is not sent to the server. The server runs the CommandQueue insert and sends the result back, at which point the client discards the results of the simulation and applies the results sent from the server, making the OtherCollection change disappear.
A better way to do this would be to write a custom method. Something like:
Meteor.methods({
auditedCommand: function (command) {
CommandQueue.insert(command);
var whatever = someProcessing(command)
OtherCollection.insert(whatever);
}
});
Then:
Meteor.call('auditedCommand', command);
This will show up immediately on the client (latency compensation) and is more secure as clients can't insert to CommandQueue without also adding to OtherCollection.
EDIT: this will probably change. The added callback shouldn't really be considered part of the local simulation of CommandQueue.insert. Thats just the way it works now. That said, a custom method is probably still a better approach for this, it will work even if other people add commands to the command queue, and is more secure.
I'm not sure about your observe behavior but we accomplished the same thing using a server-side allow method:
CommandQueue.allow ({
insert: function (userId, doc) {
OtherCollection.insert(...);
return (userId && doc.owner === userId);
}
});
This is also more secure than putting this logic client side.

How can I terminate a QThread

Recently ,I come across this problem as I memtioned in this Title.
I have tried by using QThread::terminate(),but I just can NOT stop
the thread ,which is in a dead loop (let's say,while(1)).
thanks a lot.
Terminating the thread is the easy solution to stopping an async operation, but it is usually a bad idea: the thread could be doing a system call or could be in the middle of updating a data structure when it is terminated, which could leave the program or even the OS in an unstable state.
Try to transform your while(1) into while( isAlive() ) and make isAlive() return false when you want the thread to exit.
QThreads can deadlock if they finish "naturally" during termination.
For example in Unix, if the thread is waiting on a "read" call, the termination attempt (a Unix signal) will make the "read" call abort with an error code before the thread is destroyed.
That means that the thread can still reach it's natural exit point while being terminated. When it does so, a deadlock is reached since some internal mutex is already locked by the "terminate" call.
My workaround is to actually make sure that the thread never returns if it was terminated.
while( read(...) > 0 ) {
// Do stuff...
}
while( wasTerminated )
sleep(1);
return;
wasTerminated here is actually implemented a bit more complex, using atomic ints:
enum {
Running, Terminating, Quitting
};
QAtomicInt _state; // Initialized to Running
void myTerminate()
{
if( _state.testAndSetAquire(Running, Terminating) )
terminate();
}
void run()
{
[...]
while(read(...) > 0 ) {
[...]
}
if( !_state.testAndSetAquire(Running, Quitting) ) {
for(;;) sleep(1);
}
}
Have you tried exit or quit?
Did the thread call QThread::setTerminationEnabled(false)? That would cause thread termination to delay indefinitely.
EDIT: I don't know what platform you're on, but I checked the Windows implementation of QThread::terminate. Assuming the thread was actually running to begin with, and termination wasn't disabled via the above function, it's basically a wrapper around TerminateThread() in the Windows API. This function accepts disrespect from no thread, and tends to leave a mess behind with resource leaks and similar dangling state. If it's not killing the thread, you're either dealing with zombie kernel calls (most likely blocked I/O) or have even bigger problems somewhere.
To use unnamed pipes
int gPipeFdTest[2]; //create a global integer array
As an when where you intend to create pipes use
if( pipe(gPipeFdTest) < 0)
{
perror("Pipe failed");
exit(1);
}
The above code will create a pipe which has two ends gPipeFdTest[0] for reading and gPipeFdTest[1] for writing. What you can do is in your run function set up to read the pipe using select system call. And from where you want to come out of run, there set up to write using write system call. I have used select system call for monitoring the read end of the pipe as it suits my implmentation. Try to figure all this out in your case. If you need any more help, give me a buzz.
Edit:
My problem was just like yours. I had a while(1) loop and the other things I tried needed mutexes and other fancy multithreading mumbo jumbo, which added complexity and debugging was nightmare. Using pipes absolved me from those complexities besides simplified the code. I am not saying that it is the best option but in my case it turned out to be the best and cleanest alternative. I was bugged my hung application before this solution.

Resources