Ley's say we have a service:
interface ExceptionService : Service {
fun doSmth(flag: Boolean)
}
implementation:
class ExceptionServiceImpl : ExceptionService {
override fun doSmth(flag: Boolean) {
if (flag) {
throw IOException("my IO exception")
} else {
throw IllegalArgumentException("my IllegalArgument exception")
}
}
}
We deploy it onto Ignite cluster:
Ignition.start(
IgniteConfiguration()
.setServiceConfiguration(
ServiceConfiguration()
.setService(ExceptionServiceImpl())
.setName("service")
)
)
And now we call it from client:
val client = Ignition.startClient(ClientConfiguration().setAddresses("127.0.0.1"))
val service = client.services().serviceProxy("service", ExceptionService::class.java)
try {
service.doSmth(true)
} catch (e: Exception) {
println(e.mesaage)
}
try {
service.doSmth(false)
} catch (e: Exception) {
println(e.mesaage)
}
Console output will be:
Ignite failed to process request [1] my IO exception (server status code [1])
Ignite failed to process request [2] my IllegalArgument exception (server status code [1])
The problem is that the type of the caught exception is always org.apache.ignite.client.ClientException. The only thing that left from the original exceptions thrown on server is message, and even it is wrapped in other words. The cause is of type org.apache.ignite.internal.client.thin.ClientServerError. Types are lost.
I want to handle on client side different types of exceptions thrown by service. Is there a way to do it? Maybe some Ignite configuration that I missed?
Try enabling ThinClientConfiguration#sendServerExceptionStackTraceToClient
I have a filter created where I access the body of the payload and do some logic on it (for now let's say I log the body). In the last step, I return Mono but when the request proceeds through the controller to services it throws a bad request error that the body is missing.
Code for the filter:
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
HttpHeaders headers = serverWebExchange.getRequest().getHeaders();
String domain = headers.getFirst("domain");
return serverWebExchange.getRequest().getBody()
.single()
.flatMap(body -> Mono.just(parseBody(body)))
.flatMap(s -> webFilterChain.filter(serverWebExchange));
}
private String parseBody(DataBuffer fbody) {
System.out.println("parsing body");
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
Channels.newChannel(baos).write(fbody.asByteBuffer().asReadOnlyBuffer());
} catch (IOException e) {
e.printStackTrace();
}
return baos.toString(StandardCharsets.UTF_8);
}
The error: org.springframework.web.server.ServerWebInputException: 400 BAD_REQUEST "Request body is missing"
What can cause this behavior?
The reason is that you can only read the body once (https://github.com/spring-cloud/spring-cloud-gateway/issues/1587)
You are reading it here: serverWebExchange.getRequest().getBody() and therefore it is omitted in the request.
A solution is to cache the body, you can use for instance the ReadBodyRoutePredicateFactory (https://github.com/spring-cloud/spring-cloud-gateway/issues/1307).
Make sure the RemoveCachedBodyFilter is enabled so the body is released so you do not have memory leaks.
I wanted to retry in case of any exception from the service. But when using retryWhen am getting exception java.lang.IllegalStateException: UnicastProcessor allows only a single Subscriber.
Without retry, its working fine
Flux.window(10)
.flatMap(
windowedFlux ->
webclient.post().uri(url)
.body(BodyInserters.fromPublisher(windowedFlux, Request.class))
.exchange()
.doOnNext(ordRlsResponse -> {
if( ordRlsResponse.statusCode().is2xxSuccessful()) {
Mono<ResponseEntity<Response>> response = ordRlsResponse.toEntity(Response.class);
//doing some processing here
}
else {
throw new CustomeException(errmsg);
}
}).retryWhen(retryStrategy)).subscribe();
And my retryStrategy is defined like:
Retry retryStrategy = Retry.fixedDelay((long)5, Duration.ofSeconds((long)5))
.filter(exception -> exception instanceof CustomeException)
.doAfterRetry( exception -> log.info("Retry attempted"))
I'm subscribing to a MQTT Topic(in my case it is app unique user id).I'm using AWS IOT core services for subscription.Whenever home screen opens up and I got connected callback from awsConnectClient,I make the call for subscription. Now what is happening if app gets open up three times It subscribed to the same topic 3 time.Now whenever any message publish to that topic.It received by app 3 times.
Now what I want to do that I want to know that if this userId is already subscribed from this device I would not make a call for subscription again from same device.
One approach could be If I save in my app that I had already subscribed to this topic and do not make the call for subscription again. but I doubt if this approach could be correct for all scenarios.Could it be possible that we could drive this logic from the server end only, if any aws iot api could give me that this is already subscribed.
fun connectClick() {
Log.d(TAG, "clientId = $clientId")
try {
mqttManager.connect(clientKeyStore) { status, throwable ->
Log.d(TAG, "Status = " + status.toString())
var formattedStatus = String.format(getString(R.string.status_msg),status.toString())
if (status == AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus.Connected) {
Log.i(TAG, " subscribed to - " + VoiceXPreference(this).rosterName)
unsubscribe()
subscribeClick(VoiceXPreference(this).rosterName)
}
runOnUiThread {
tv_iot_status.text = formattedStatus
if (throwable != null) {
Log.e(TAG, "Connection error.", throwable)
}
}
}
} catch (e: Exception) {
Log.e(TAG, "Connection error.", e)
}
}
Above is my subscription code.Although I'm always unsubscribing before subscribing but this is not working for me.
Following is my initClient call which makes the connection request. I have added the if check if mqttManager is already initialised first disconnect and then make connect request. Although I have put initRequest inside onCreate() call back of app screen which calls only once when the app opens up. I have checked the logs it is being called only once.
AWSMobileClient.getInstance().initialize(this, object : Callback<UserStateDetails> {
override fun onResult(result: UserStateDetails) {
Log.i(TAG,"connect request called");
if(mqttManager != null){
mqttManager?.disconnect()
}
initIoTClient()
}
override fun onError(e: Exception) {
Log.e(TAG, "onError: ", e)
}
})
Following is my subscribe code snippet which is subscribing to unique userId
fun subscribeClick(topic: String) {
Log.d(TAG, "topic = $topic")
try {
mqttManager?.subscribeToTopic(topic, AWSIotMqttQos.QOS0,
{ topic, data ->
runOnUiThread {
try {
val message = String(data, Charsets.UTF_8)
Log.d(TAG, "Message arrived:")
Log.d(TAG, " Topic: $topic")
Log.d(TAG, " Message: $message")
val gson = Gson()
val notificationModel = gson.fromJson(message, NotificationModel::class.java)
var orderServiceMapperResponseModel = OrderServiceMapperResponseModel()
orderServiceMapperResponseModel.seatId = notificationModel.seatId
orderServiceMapperResponseModel.serviceName = notificationModel.service
orderServiceMapperResponseModel.id = notificationModel.id
orderServiceMapperResponseModel.createdDate = notificationModel.createdDate
serviceList.add(orderServiceMapperResponseModel)
if (isPictureInPictureMode) {
if (isShownNotification) {
updateNotificationCount()
} else {
updatePIPWindowContent()
}
} else {
updateAdapterDataSource()
}
} catch (e: UnsupportedEncodingException) {
Log.e(TAG, "Message encoding error.", e)
}
}
})
} catch (e: Exception) {
Log.e(TAG, "Subscription error.", e)
}
}
I'm also always making disconnect() request inside onDestroy() of my app screen
mqttManager?.disconnect()
But Still I'm getting 3 subscription messages instead of 1.
You receive 3 duplicated messages not because you subscribe 3 times but because you create 3 individual connections.
The MQTT specification clearly states that
If a Server receives a SUBSCRIBE Packet containing a Topic Filter that is identical to an existing Subscription’s Topic Filter then it MUST completely replace that existing Subscription with a new Subscription.
meaning duplicated subscriptions per connection never happen, unless the server has a broken implementation.
Your code looks like that it never send disconnect requests while a new connection is created whenever the code block is invoked.
You should keep a single MQTT session, or make sure you close the connection when the app is closed.
Our application is storing data the user enters in SalesForce. We are using Spring AMQP (RabbitMQ) to be able to store data and run the application even if SalesForce is not reachable (scheduled downtimes or else).
So once SalesForce is not available the queue should wait with retrying messages until it is up again. Is this possible using the CircuitBreakerRetryPolicy or do i have to implement a custom RetryPolicy?
Currently i just have a simply retry policy which should be replaced by a complex one that blocks the retries until the external system is reachable again.
#Bean
RetryOperationsInterceptor salesForceInterceptor() {
return RetryInterceptorBuilder.stateless()
.recoverer(new RejectAndDontRequeueRecoverer())
.retryPolicy(simpleRetryPolicy())
.build();
}
Message listener:
#Override
public void onMessage(Message message) {
try {
.....
} catch (ResourceAccessException e) {
//TODO probablyy wrong exception
throw new AmqpTimeoutException("Salesforce can not be accessed, retry later");
} catch (Exception e) {
throw new AmqpRejectAndDontRequeueException("Fatal error with message to salesforce, do not retry", e);
}
}