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

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.

Related

Handling connection failures with IO::Socket::Async

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.

In Disassembler pipeline component - Send only last message out from GetNext() method

I have a requirement where I will be receiving a batch of records. I have to disassemble and insert the data into DB which I have completed. But I don't want any message to come out of the pipeline except the last custom made message.
I have extended FFDasm and called Disassembler(), then we have GetNext() which is returning every debatched message out and they are failing as there is subscribers. I want to send nothing out from GetNext() until Last message.
Please help if anyone have already implemented this requirement. Thanks!
If you want to send only one message on the GetNext, you have to call on Disassemble method to the base Disassemble and get all the messages (you can enqueue this messages to manage them on GetNext) as:
public new void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
{
try
{
base.Disassemble(pContext, pInMsg);
IBaseMessage message = base.GetNext(pContext);
while (message != null)
{
// Only store one message
if (this.messagesCount == 0)
{
// _message is a Queue<IBaseMessage>
this._messages.Enqueue(message);
this.messagesCount++;
}
message = base.GetNext(pContext);
}
}
catch (Exception ex)
{
// Manage errors
}
Then on GetNext method, you have the queue and you can return whatever you want:
public new IBaseMessage GetNext(IPipelineContext pContext)
{
return _messages.Dequeue();
}
The recommended approach is to publish messages after disassemble stage to BizTalk message box db and use a db adapter to insert into database. Publishing messages to message box and using adapter will provide you more options on design/performance and will decouple your DB insert from receive logic. Also in future if you want to reuse the same message for something else, you would be able to do so.
Even then for any reason if you have to insert from pipeline component then do the following:
Please note, GetNext() method of IDisassembler interface is not invoked until Disassemble() method is complete. Based on this, you can use following approach assuming you have encapsulated FFDASM within your own custom component:
Insert all disassembled messages in disassemble method itself and enqueue only the last message to a Queue class variable. In GetNext() message then return the Dequeued message, when Queue is empty return null. You can optimize the DB insert by inserting multiple rows at a time and saving them in batches depending on volume. Please note this approach may encounter performance issues depending on the size of file and number of rows being inserted into db.
I am calling DBInsert SP from GetNext()
Oh...so...sorry to say, but you're doing it wrong and actually creating a bunch of problems doing this. :(
This is a very basic scenario to cover with BizTalk Server. All you need is:
A Pipeline Component to Promote BTS.InterchageID
A Sequential Convoy Orchestration Correlating on BTS.InterchangeID and using Ordered Delivery.
In the Orchestration, call the SP, transform to SOAP, call the SOAP endpoint, whatever you need.
As you process the Messages, check for BTS.LastInterchagneMessage, then perform your close out logic.
To be 100% clear, there are no practical 'performance' issues here. By guessing about 'performance' you've actually created the problem you were thinking to solve, and created a bunch of support issues for later on, sorry again. :( There is no reason to not use an Orchestration.
As noted, 25K records isn't a lot. Be sure to have the Receive Location and Orchestration in different Hosts.

Should I use Thread.Sleep or Task.Delay in a nopcommerce Task?

I am coding a Task in a plugin to nopcommerce. The Task must download a catalogue from a website (https://data.icecat.biz/export/level4/). If the download fail for some reason, I want my program to wait for a minute and then try again a couple of times.
e.g
while(notTiredOfWaiting)
{
try{
// my download stuff here
return data;
}
catch(Exception e)
{
Thread.Sleep(60000);
// or
Task.Delay(60000);
}
}
My problem is that nopcommerce is some kind of blackbox, which starts and run my task. The "easy" solution is to use Thread.Sleep(), but I don't know if any other important processes runs on the same thread. I have tried Task.Delay(), but it doesn't seem to work in my implementation.
I known that Thread.Sleep versus Task.Delay() is a hot topic on SO, but I am asking for a specific answer for what is best practice in nopCommerce.
Edit.
The task is using IScheduleTaskService.
I think the best option for the retrying operation is a System.Threading.Timer, you doesn't need to worry about nopcommerce threading behaviour and you let .net to manage the threading stuff, you can use something like:
void Retry(){
if(notTiredOfWaiting)
{
var timer = new System.Threading.Timer((cb) => { Retry() }, null, 60000, 0);
}
}
Icecat is a quite big catalog, so I'm not surprised you're getting trouble with it.
You could change your algorithm to something like:
Set your task to run at short intervals, for instance every 15 minutes.
Try to acquire a lock at the beginning of the task; if the lock is taken then the previous task is still running, just return without processing.
If the lock is not taken, acquire the lock, and check the last time the process ended. If enough time has passed, run your task (1 day, 1 week, or the amount of time you may need between downloads). You need to store the last time somewhere: you can use one of your own tables, or a custom setting would do just fine.
If the task was successful, save the new ending time.
Release the lock.
Maybe you would like to add a limit to the times you retry. And some logging.
// Sample pseudocode
if (Monitor.TryEnter(lockObj)) {
try {
if (EnoughTimeHasPassed())
{
DownloadIcecat();
SaveLastFinishingTime(now);
}
}
finally { Monitor.Exit(lockObj); }
}

Can a thread in ASP.NET work keep continue after Response.End?

I want to make a tcp connection to a device and keep continously retrieve data from device. I want to start this with a simple request and keep it working background even Page response completed. Is this possible in asp.net?
Can a thread in ASP.NET work keep continue after Response.End?
Yes, you can if you do not care or do not need the result.
For example, in the following code, you call AddLogAsync and insert a log, but you not care whether insert successful or not.
public Task AddLogAsync(Log log)
{
return Task.Run(() => AddLog(log));
}
private void AddLog(TraceLog traceLog)
{
// Do something here.
}
I want to make a tcp connection to a device and keep continously
retrieve data from device. I want to start this with a simple request
and keep it working. Is this possible in asp.net?
I'm not really understanding above question. After Response.End, you cannot return anything, although you can continue work on something in different thread.

Adobe Air SQLite synchronous busy timeout / SQLite concurrent access / avoid busy loop

this is my first post here. I'm asking because I ran out of clues and I was unable to find anything about this specific issue.
My question is: In Adobe AIR, is there a way to do a synchronous usleep() equivalent (delay execution of 200ms), alternatively is there a way to specify the SQLite busy timeout somewhere?
I have an AIR application which uses the database in synchronous mode because the code cannot cope with the need of events/callbacks in SQL queries.
The database sometimes is accessed from another application, such that it is busy. Hence the execute() of a statement throws SQLerror 3119 detail 2206. In this case the command shall be retried after a short delay.
As there is another application running on the computer I want to try to avoid busy waiting, however I'm stuck with it because of three things:
First, I was unable to find a way to give the SQLConnection a busy timeout value, like it is possible in C with the function sqlite3_busy_timeout()
Second, I was unable to find the equivalent of the C usleep() command in Adobe AIR / Actionscript.
Third, I am unable to use events/timers/callbacks etc. at this location. The SQL execute() must be synchronous because it is called from deeply nested classes and functions in zillion of places all around in the application.
If the application could cope with events/callbacks while doing SQL I would use an asynchronous database anyway, so this problem cannot be solved using events. The retry must be done on the lowest level without using the AIR event processing facility.
The lowest level of code looks like:
private static function retried(fn:Function):void {
var loops:int = 0;
for (;;) {
try {
fn();
if (loops)
trace("database available again, "+loops+" loops");
return;
} catch (e:Error) {
if (e is SQLError && e.errorID==3119) {
if (!loops)
trace("database locked, retrying");
loops++;
// Braindead AIR does not provide a synchronous sleep
// so we busy loop here
continue;
}
trace(e.getStackTrace());
trace(e);
throw e;
}
}
}
One sample use of this function is:
protected static function begin(conn:SQLConnection):void {
retried(function():void{
conn.begin(SQLTransactionLockType.EXCLUSIVE);
});
}
Output of this code is something like:
database locked, retrying
database available again, 5100 loops
Read: The application loops over 500 times a second. I would like to reduce this to 5 loops somehow to reduce CPU load while waiting, because the App shall run on Laptops while on battery.
Thanks.
-Tino

Resources