UndeliverableException thrown within a RxAndroidBle stream - rx-java2

I have a misbehaving BLE device (temp sensor) that keeps throwing a status 8 (GATT_INSUF_AUTHORIZATION or GATT_CONN_TIMEOUT) exception everytime i try to connect to the device. I'm not concerned about this exception as the device is faulty.
However, I keep getting notified that i've not handled the error correctly by rxjava2 when using RxAndroidBle(1.9.1); see here;
This is my code.
rxBleClient
.getBleDevice(macAddress)
.establishConnection(false)
.flatMapSingle { it.readRssi() }
.subscribe({ "test1:Success" }, { "test1:error" })
and the Error
I/RxBle#GattCallback: MAC='E9:CF:8A:D0:01:19' onConnectionStateChange(), status=8, value=0
D/RxBle#ClientOperationQueue: FINISHED ConnectOperation(147547253) in 10257 ms
D/RxBle#ConnectionOperationQueue: Connection operations queue to be terminated (MAC='E9:CF:8A:D0:01:19')
com.polidea.rxandroidble2.exceptions.BleDisconnectedException: Disconnected from MAC='E9:CF:8A:D0:01:19' with status 8 (GATT_INSUF_AUTHORIZATION or GATT_CONN_TIMEOUT)
at com.polidea.rxandroidble2.internal.connection.RxBleGattCallback$2.onConnectionStateChange(RxBleGattCallback.java:77)
at android.bluetooth.BluetoothGatt$1$4.run(BluetoothGatt.java:249)
at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:725)
at android.bluetooth.BluetoothGatt.-wrap0(Unknown Source:0)
at android.bluetooth.BluetoothGatt$1.onClientConnectionState(BluetoothGatt.java:244)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:70)
at android.os.Binder.execTransact(Binder.java:697)
D/BleDeviceManagerNew$observeRssiTest: test1:error
E/plication$setupApp: Terminal Exception From RXJAVA was Not handled correctly
io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | com.polidea.rxandroidble2.exceptions.BleDisconnectedException: Disconnected from MAC='E9:CF:8A:D0:01:19' with status 8 (GATT_INSUF_AUTHORIZATION or GATT_CONN_TIMEOUT)
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
at io.reactivex.internal.operators.observable.ObservableUnsubscribeOn$UnsubscribeObserver.onError(ObservableUnsubscribeOn.java:67)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onError(ObservableSubscribeOn.java:63)
I'm not sure what else I should do - i've implemented a 'catch all' solution but don't like this approach;
RxJavaPlugins.setErrorHandler { e -> Timber.e(e, "Terminal Exception From RXJAVA was Not handled correctly") }
but don't see that as a good solution as expected that i should be-able to handle exception on the steam. Any suggestions of where I went wrong?

Your code is fine. The library has a flaw that does not allow to achieve your desired behaviour. More on the topic is on this library's wiki page.
While it is possible to design an API that would not throw UndeliverableException it would need to have a separate error Observable or Completable for BluetoothAdapter turning off and a separate one for RxBleConnection disconnect. The user would be responsible to mix those into their chain appropriately.
Current API does not allow it.

Related

Unable to sync after Amplify.Datastore.clear()

I have a home page that does the initial datastore sync in the init() function. There are QueryPredicates that are based on a variable that can change (on a different page).
So basically, after I start the app, everything syncs correctly. Then, I go to another page and change the value that those QueryPredicates depend on, but the sync doesn't occur. Instead, I get an error (that I'm almost positive is caused from the datastore.clear()).
Here is a look at what the QueryPredicate and value change looks like...
List<String> variableThatChanges = ['initialValue']; // belongs to a global class instance
QueryPredicate sampleTest() {
QueryPredicate res = Sample.AUTHGROUP
.eq(variableThatChanges.isEmpty ? '' : variableThatChanges[0]);
return res;
}
// And when the value is changed, it's changed like this...
variableThatChanges = ['newValue'].toList(); // Not sure if .toList() is actually necessary or not
And this is the rest of the logic...
// Change the variable value, then...
await Amplify.DataStore.stop();
await Amplify.DataStore.clear();
await Amplify.DataStore.start();
Amplify.DataStore.listen([HubChannel.DataStore], (msg) {// do things with the events});
await Amplify.DataStore.save("basic log message to log the change and initiate sync if hasn't already happened");
NOTE: I actually have these commands wrapped in a try/catch and have some other small things going on so each of the above commands is in it's own function and I call them in the following way...
stopStore().then((_) => clearStore()).then((_) => startStore()).then((_) => listenToHub()).then((_) => logEvent());
The error that is produced is the following:
I/amplify:aws-api(11613): No more active subscriptions. Closing web socket.
W/amplify:aws-api(11613): Thread interrupted awaiting subscription acknowledgement.
W/amplify:aws-api(11613): at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos(AbstractQueuedSynchronizer.java:1081)
W/amplify:aws-api(11613): at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1369)
W/amplify:aws-api(11613): at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:278)
W/amplify:aws-api(11613): at com.amplifyframework.api.aws.SubscriptionEndpoint$Subscription.awaitSubscriptionReady(SubscriptionEndpoint.java:381)
W/amplify:aws-api(11613): at com.amplifyframework.api.aws.SubscriptionEndpoint.requestSubscription(SubscriptionEndpoint.java:183)
W/amplify:aws-api(11613): at com.amplifyframework.api.aws.MutiAuthSubscriptionOperation.dispatchRequest(MutiAuthSubscriptionOperation.java:113)
W/amplify:aws-api(11613): at com.amplifyframework.api.aws.MutiAuthSubscriptionOperation.$r8$lambda$iziEcYpvlINdYbit2it7fDbbt8A(Unknown Source:0)
W/amplify:aws-api(11613): at com.amplifyframework.api.aws.MutiAuthSubscriptionOperation$$ExternalSyntheticLambda4.run(Unknown Source:2)
W/amplify:aws-api(11613): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:463)
W/amplify:aws-api(11613): at java.util.concurrent.FutureTask.run(FutureTask.java:264)
W/amplify:aws-api(11613): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
W/amplify:aws-api(11613): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
W/amplify:aws-api(11613): at java.lang.Thread.run(Thread.java:1012)
D/TrafficStats(11613): tagSocket(71) with statsTag=0xffffffff, statsUid=-1
E/amplify:aws-datastore(11613): Failure encountered while attempting to start API sync.
...
W/amplify:aws-datastore(11613): API sync failed - transitioning to LOCAL_ONLY.
...
I/amplify:aws-datastore(11613): Orchestrator transitioning from SYNC_VIA_API to LOCAL_ONLY
I/amplify:aws-datastore(11613): Setting currentState to LOCAL_ONLY
I/amplify:aws-datastore(11613): Stopping subscription processor.
Of note, the only other time we use Datastore.clear() in our app is prior to the the user signing out, and the same No more active subscriptions. Closing web socket. message comes up.
Any help at figuring out how to fix this to allow for the re-sync after changing the QueryPredicate value would really be appreciated.
It's weird, a lot of times, if I go back to the homepage the init() code with run again and then things start working as desired. This isn't all the time, but most of the time. The thing about that is, that I believe Amplify.configure() is being called again (which I know isn't recommended to do more than once in the apps lifecycle).
I've tried everything listed above, but can't get the subscription error to go away and the app to re-sync correctly.
The end goal is to be able to clear the datastore and get a fresh sync using the new variable in the QueryPredicate.
After reviewing open tickets in the amplify-flutter github repo I came across this one:
https://github.com/aws-amplify/amplify-flutter/issues/1479
Basically, you can't await Datastore.clear() or Datastore.close() (on Android). It's a bug that is supposed to be being worked on, but the ticket is still open and it'll be a year next month, so who knows when it'll be fixed.
Anyways, one of the suggestions in there is to simply implement a manual delay of 2 seconds after you call Datastore.clear().
I ended up doing this after both of my calls, (Datastore.stop() and Datastore.clear()) and everything works just fine now. It's just a timing issue with the asynchronous functions.
So, as mentioned, this isn't the best solution, but until the amplify-flutter team implements a fix, this seems to be a valid workaround.

R2DBC MSSQL r2dbc.mssql.client.ReactorNettyClient : Connection has been closed by peer

I have started to work on a Spring WebFlux and R2DBC project. Mainly, my code works fine.
But after some elements I am receiving this warning
r2dbc.mssql.client.ReactorNettyClient : Connection has been closed by peer
after this warning I am getting this exception and normally program stops to read from Flux which source is R2DBC driver.
ReactorNettyClient$MssqlConnectionClosedException: Connection unexpectedly closed
My main pipeline like this;
Sinks.Empty<Void> completionSink = Sinks.empty();
Flux<Event> events = service.getPairs(
taskProperties.A,
taskProperties.B);
events
.flatMap(some operation)
.doOnComplete(() -> {
log.info("Finished Job");
completionSink.emitEmpty(Sinks.EmitFailureHandler.FAIL_FAST);
})
.subscribe();
completionSink.asMono().block();
After run, flatMap requesting 256 element as a default, then after fetching trying to request(1) for next signal.
At somewhere between 280. and 320. element it is getting above error. It is not idempotent, sometimes it reads 280 element sometimes it is reading 303, 315 etc.
I think it is about network maybe? But not sure and cannot find the reason. Do I need a pool or something different?
Sorry if I missed anything, in case you want I will try to update here.
Thank you in advance
I have tried to change request size of flatMap to unbounded, adding scheduler, default r2dbc pool but for now I don't have any clue.

Checking health of Kafka Stream Threads

When some of the stream threads die (because of an exception for example), I don't want to continue, but restart the process.
In order to do this, I need to identify this state.
I know I can use kafkaStream.state(), but it checks the state of the whole kstreams. Meaning if only one StreamThread has died, it will not be discovered by kafkaStream.state().
What is the best way for me to know in the code that all StreamThreads are alive and working?
Update : adding timeout to KafkaStreams#close() as it can cause deadlock as Matthias stated in the comment
If you want to detect if any StreamThreads has dies then you can use KafkaStreams#setUncaughtExceptionHandler(), you can stop streaming and exit app:
kafkaStreams.setUncaughtExceptionHandler((t, e) -> {
logger.error("Exiting ", e);
kafkaStreams.close(10);
System.exit(1);//exit with error code so container can restart this app
});

Opencascade crash when calling calling Transfer()

I have tested two cases:
I use STEPCAFControl_Reader then STEPControl_Reader to read my step file but both methods crash when I call STEPCAFControl_Reader::Transfer, repsectively STEPControl_Reader:: TransferRoots.
By using STEPControl_Reader, I displayed a log on my console, then there is a message like this:
1 F:(BOUNDED_SURFACE,B_SPLINE_SURFACE,B_SPLINE_SURFACE_WITH_KNOTS,GEOMETRIC_REPRESENTATION_ITEM,RATIONAL_B_SPLINE_SURFACE,REPRESENTATION_ITEM,SURFACE): Count of Parameters is not 1 for representation_item
EDIT:
There is a null reference inside TransferRoots() method.
const Handle(Transfer_TransientProcess) &proc = thesession->TransferReader()->TransientProcess();
if (proc->GetProgress().IsNull())
{
//This condition does not exist from the source code
std::cout << "GetProgress is null" << std::endl;
return 0;
}
Message_ProgressSentry PS ( proc->GetProgress(), "Root", 0, nb, 1 );
My app and FreeCAD crash but if I use CAD Assitant which OCC official viewer, it loads.
It looks like comments already provide an answer to the question - or more precisely answers:
STEPCAFControl_Reader::ReadFile() returns reading status, which should be checked before calling STEPCAFControl_Reader::Transfer().
Normally, it is a good practice to put OCCT algorithm into try/catch block and check for OCCT exceptions (Standard_Failure).
Add OCC_CATCH_SIGNALS at the beginning of try statements (required only on Linux) and OSD::SetSignal(false) within working thread creation to redirect abnormal cases (access violation, NULL dereference and others) to C++ exceptions (OSD_Signal which is subclass of Standard_Failure). This may conflict other signal handlers in mixed environment - so check also documentation of other frameworks used by application.
If you catch failures like NULL dereference on calling OCCT algorithm with valid arguments - this is a bug in OCCT which is desirable to be fixed in one or another way, even if input STEP file contains syntax/logical errors triggering such kind of issues. Report the issue on OCCT Bugtracker with sufficient information for reproducing bug, including sample files - it is not helpful to developers just saying that OCCT crashes somewhere. Consider also contributing into this open source project by debugging OCCT code and suggesting patches.
Check STEP file reading log for possible errors in the file itself. Consider reporting an issue to system producing a broken file, even if main file content can be loaded by STEP readers.
It is a common practice to use OSD::SetSignal() within OCCT-based applications (like CAD Assistant) to improve their robustness on non-fatal errors in application/OCCT code. It is more user friendly reporting an internal error message instead of silently crashing.
But it should be noted, that OSD::SetSignal() doesn't guarantee application not being crashed nor that application can work properly after catching such failure - due to asynchronous nature of some signals, the memory can be already corrupted at the moment, when C++ exception has been raised leading to all kinds of undesired behavior. For that reason, it is better not ignoring such kind of exceptions, even if it looks like application works fine with them.
OSD::SetSignal(false); // should be called ones at application startup
STEPCAFControl_Reader aReader;
try
{
OCC_CATCH_SIGNALS // necessary for redirecting signals on Linux
if (aReader.ReadFile (theFilePath) != IFSelect_RetDone) { return false; }
if (!aReader.Transfer (myXdeDoc)) { return false; }
}
catch (Standard_Failure const& theFailure)
{
std::cerr << "STEP import failed: " << theFailure.GetMessageString() << "\n";
return false;
}
return true;

Indy - ReadLnSplit Causes NotConnected Exception when closing

I use TIdTCPServer and the following code to read client input :
repeat
cl3:=cl3+AContext.Connection.IOHandler.ReadLnSplit(WasSplit,#0,-1,-1,TEncoding.UTF8);
until not WasSplit;
However if client is connected to the server and I close the server it raises an exception class (EIdNotConnected) whith message 'Not connected'.
If I use ReadLn instead ReadLnSplit no exception raises.
What causes this exception and how could I prevent it?
I suppose the solution is simple but I am new to sockets and Indy and I cant figure it out.
Thanks in advance.
What is the actual problem? When you close the server, it is supposed to make active reading/writing operations raise an exception. That is normal behavior for Indy. ReadLn() is just as likely to raise an exception as ReadLnSplit() is. Indy relies on exceptions for its internal notifications. Just let the server handle the exception for you, so it can terminate and cleanup the thread that is managing the TIdContext and its connection. The exception is in the context of that thread, the rest of your code (or your users) will not see it.
The only thing ReadLnSplit() does differently than ReadLn() is to force the IOHandler's MaxLineAction property to maSplit during that call, nothing else. The only reason to use ReadLnSplit() is to handle lines that are longer than the IOHandler's MaxLineLength property without changing the MaxLineLength. If you don't like the way ReadLnSplit() behaves, then don't use it. You could just increase the value of the IOHandler's MaxLineLength property and call ReadLn() instead:
AContext.Connection.IOHandler.MaxLineLength := MaxInt;
cl3 := AContext.Connection.IOHandler.ReadLn(#0, IndyUTF8Encoding);
Or you could call the overloaded version of ReadLn() that has an optional AMaxLineLength parameter:
cl3 := AContext.Connection.IOHandler.ReadLn(#0, IdTimeoutDefault, MaxInt, IndyUTF8Encoding);