I have two services "product-service" and "rating-service". I am making a rest call from product-service to rating-service to get the data. I have written the Retry configuration in product-service and expecting whenever an exception raised from rating-service, product-service retry the rest call as per configuration. But it is not happening. Whenever an exception thrown from rating-service, product-service also throws the exception without retrying and also fallback. Please find below code of both the services.
Check the code of the both services here.
product-service >> ProductServiceImpl.java
#Retry(name = "rating-service", fallbackMethod = "getDefaultProductRating")
public List<ProductRatingDTO> getProductRating(String id) {
String reqRatingServiceUrl = ratingServiceUrl + "/" + id;
log.info("Making a request to " + reqRatingServiceUrl + " at :" + LocalDateTime.now());
ResponseEntity<List<ProductRatingDTO>> productRatingDTOListRE = restTemplate.exchange(reqRatingServiceUrl,
HttpMethod.GET, null, new ParameterizedTypeReference<List<ProductRatingDTO>>() {
});
List<ProductRatingDTO> productRatingDTOList = productRatingDTOListRE.getBody();
log.info("Retrieved rating for id {} are: {}", id, productRatingDTOList);
return productRatingDTOList;
}
public List<ProductRatingDTO> getDefaultProductRating(String id, Exception ex) {
log.warn("fallback method: " + ex.getMessage());
return new ArrayList<>();
}
product-service >> application.yml
resilience4j.retry:
instances:
rating-service:
maxAttempts: 3
waitDuration: 10s
retryExceptions:
- org.springframework.web.client.HttpServerErrorException
ignoreExceptions:
- java.lang.ArrayIndexOutOfBoundsException
rating-service >> RatingsServiceImpl.java
#Override
public List<RatingsDTO> getRatings(String productId) {
log.info("Ratings required for product id: "+productId);
List<RatingsDTO> ratingsDTOList = ratingsRepository.getRatingsByProductId(productId);
log.info("Ratings fetched for product id {} are : {}",productId,ratingsDTOList);
if (ThreadLocalRandom.current().nextInt(0,5) == 0){ // Erratic block
log.error("Erratic");
throw new org.springframework.web.client.HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR);
}
return ratingsDTOList;
}
Please let me know where I am doing the mistake?
Related
I am writing negative test case in which I am expecting internal server error but somehow I am not able to get it. The code i have tried and the output is posted below:
delete method:
/**
* delete pricing rule by id
* #param ruleId
* #return
*/
#DeleteMapping(path = "/deleteById/{ruleId}")
public ResponseEntity<String> deletePricingRule(#PathVariable String ruleId) {
logMethodStart(RulesCrudController.class, "deletePricingRule");
try {
log.debug( "deleting pricing rule with id: " + ruleId );
String deletedId = pricingRuleServiceImpl.deletePricingRule(ruleId);
if( deletedId != null ) {
log.debug("deleted pricing rule with id: " + ruleId);
return new ResponseEntity<>("The rule id : " + deletedId + " is deleted successfully", HttpStatus.OK);
} else {
return new ResponseEntity<>("No pricing rule with rule id: "+ ruleId +" is Found",HttpStatus.INTERNAL_SERVER_ERROR);
}
}
catch(Exception e){
log.error("deletePricingRule() got an exception: " + e.toString());
return new ResponseEntity<>("No pricing rule with rule id: "+ ruleId +" is Found",HttpStatus.INTERNAL_SERVER_ERROR);
}
}
delete test case
#Test
public void DeletePricingRule_withDeleteMethod_InternalServerError() throws Exception {
when(mockService.deletePricingRule(dynamo.getId())).thenReturn( null );
mockMVC.perform(MockMvcRequestBuilders.delete("/pricingRule/deleteById/{ruleId}", dynamo.getId()))
.andExpect(status().isInternalServerError());
}
Object that I am using:
#Mock
private PricingRule dynamo, dynamo1;
#Before
public void setUp() {
dynamo = new PricingRule();
dynamo.setId("0653cf02-6b39-40ab-a008-6efea487eb8f");
dynamo.setRuleDesc("dynamo test");
dynamo1 = new PricingRule();
dynamo1.setId("0653cf02-6b39-40ab-a008-6efea487eb8f");
dynamo1.setRuleDesc("dynamo test");
}
Output:
java.lang.AssertionError: Status
Expected :500
Actual :200
I have a Spring WebFlux application server that sends SSE to the end user infinitely while they are connected. I want to implement some kind of id validation, that relies on requesting the id from a 3rd party service, that returns Mono<Boolean>. I want to close connection with an error if the above Mono contains false.
The problem is that I can't return Mono.error() from the handleSse method (because it has to return Flux<ServerSentEvent<UserUpdateResponse>>).
How to properly send an error to the user and close the connection afterwards?
Here's my code:
#GetMapping("/sse")
public Flux<ServerSentEvent<UserUpdateResponse>> handleSse(String id) {
return usersSink.asFlux()
.filter(update -> id.equals(update.getId()))
.map(this::wrapIntoSse);
}
private ServerSentEvent<UserUpdateResponse> wrapIntoSse(UserUpdate userUpdate) {
return ServerSentEvent.builder(new UserResponse(userUpdate.getUserCode()))
.event("user-update")
.build();
}
So after struggling with this for a while I came to this solution:
#GetMapping("/sse")
public Flux<ServerSentEvent<UserUpdateResponse>> handleSse(#RequestParam(required = false) String id) {
if (StringUtils.isBlank(id)) {
throw new WebServiceRuntimeException(HttpStatus.BAD_REQUEST, "The \"id\" parameter is missing");
}
final Mono<Boolean> cached = cacheService.getgetUser(id);
return Flux.from(cached).flatMap(exists -> {
if (exists) {
return userUpdateSink.asFlux()
.filter(update -> id.equals(update.getgetUser()))
.map(this::wrapIntoSse);
}
return Flux.error(new WebServiceRuntimeException(HttpStatus.NOT_FOUND,
"The specified \"user\" does not exist: " + id + "."));
}
);
}
#GetMapping("/sse")
public Flux<ServerSentEvent> handleSse(#RequestParam(required = false) String id) {
if (StringUtils.isBlank(id)) {
throw new WebServiceRuntimeException(HttpStatus.BAD_REQUEST, "The "id" parameter is missing");
}
final Mono cached = cacheService.getgetUser(id);
return Flux.from(cached).flatMap(exists -> {
if (exists) {
return userUpdateSink.asFlux().filter(update -> id.equals(update.getgetUser())).map(this::wrapIntoSse);
}
return Flux.error(new WebServiceRuntimeException(HttpStatus.NOT_FOUND, "The specified "user" does not exist: " + id + "."));
});
}
My serser uses Java with SpringBoot and my client is an expo react native app which uses typescript.
I am really blocked by this feature: I want to sens push notifications. I tried a lot of methods, but I didn't succeed.
On the client side I am using the method described in expo documentation: https://docs.expo.dev/push-notifications/overview/.
When I use their tool to send test notifications(https://expo.dev/notifications), I receive them on my device.
I didn't manage to send notifications from my client app. I tried all I found on the Inthernet. When I used FirebaseMessagingService and I used the server key from the firebase project as token, I received the SENDER_ID_MISMATCH error.
#Service
public class FirebaseMessagingService {
private final FirebaseMessaging firebaseMessaging;
public FirebaseMessagingService(FirebaseMessaging firebaseMessaging) {
this.firebaseMessaging = firebaseMessaging;
}
public String sendNotification(Note note, String topic) throws FirebaseMessagingException {
Notification notification = Notification
.builder()
.setTitle(note.getSubject())
.setBody(note.getContent())
.setImage(note.getImage())
.build();
Message message = Message
.builder()
.setNotification(notification)
.putAllData(note.getData())
.setToken(topic)
.build();
return firebaseMessaging.send(message);
}
}
I also found the expo-server-sdk-java but I couldn't manage to integrate it.
Any heeeeelp, pleaseeee?
not sure if it's the best practice but it works fine for me.
My pom
<dependency>
<groupId>io.github.jav</groupId>
<artifactId>expo-server-sdk</artifactId>
<version>1.1.0</version>
</dependency>
Then in the java class
private static void sendPushNotification(String token, String titulo, String mensaje, Map<String, Object> data) throws PushClientException {
if (!PushClient.isExponentPushToken(token)) throw new Error("Token:" + token + " is not a valid token.");
ExpoPushMessage expoPushMessage = new ExpoPushMessage();
expoPushMessage.getTo().add(token);
expoPushMessage.setTitle(titulo);
expoPushMessage.setBody(mensaje);
expoPushMessage.setData(data);
List<ExpoPushMessage> expoPushMessages = new ArrayList<>();
expoPushMessages.add(expoPushMessage);
PushClient client = new PushClient();
List<List<ExpoPushMessage>> chunks = client.chunkPushNotifications(expoPushMessages);
List<CompletableFuture<List<ExpoPushTicket>>> messageRepliesFutures = new ArrayList<>();
for (List<ExpoPushMessage> chunk : chunks) {
messageRepliesFutures.add(client.sendPushNotificationsAsync(chunk));
}
// Wait for each completable future to finish
List<ExpoPushTicket> allTickets = new ArrayList<>();
for (CompletableFuture<List<ExpoPushTicket>> messageReplyFuture : messageRepliesFutures) {
try {
allTickets.addAll(messageReplyFuture.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
List<ExpoPushMessageTicketPair<ExpoPushMessage>> zippedMessagesTickets = client.zipMessagesTickets(expoPushMessages, allTickets);
List<ExpoPushMessageTicketPair<ExpoPushMessage>> okTicketMessages = client.filterAllSuccessfulMessages(zippedMessagesTickets);
String okTicketMessagesString = okTicketMessages.stream().map(p -> "Title: " + p.message.getTitle() + ", Id:" + p.ticket.getId()).collect(Collectors.joining(","));
LOGGER.info("Recieved OK ticket for " + okTicketMessages.size() + " messages: " + okTicketMessagesString);
List<ExpoPushMessageTicketPair<ExpoPushMessage>> errorTicketMessages = client.filterAllMessagesWithError(zippedMessagesTickets);
String errorTicketMessagesString = errorTicketMessages.stream().map(p -> "Title: " + p.message.getTitle() + ", Error: " + p.ticket.getDetails().getError()).collect(Collectors.joining(","));
LOGGER.error("Recieved ERROR ticket for " + errorTicketMessages.size() + " messages: " + errorTicketMessagesString);
/**
// Countdown 30s
int wait = 30;
for (int i = wait; i >= 0; i--) {
System.out.print("Waiting for " + wait + " seconds. " + i + "s\r");
Thread.sleep(1000);
}
System.out.println("Fetching reciepts...");
List<String> ticketIds = (client.getTicketIdsFromPairs(okTicketMessages));
CompletableFuture<List<ExpoPushReceipt>> receiptFutures = client.getPushNotificationReceiptsAsync(ticketIds);
List<ExpoPushReceipt> receipts = new ArrayList<>();
try {
receipts = receiptFutures.get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
System.out.println("Recieved " + receipts.size() + " receipts:");
for (ExpoPushReceipt reciept : receipts) {
System.out.println("Receipt for id: " + reciept.getId() + " had status: " + reciept.getStatus());
}
*/
}
In the App.js from react native project with EXPO 44 i take expo token in this way
async function registerForPushNotificationsAsync() {
let token;
if (isDevice) {
const { status: existingStatus } =
await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== "granted") {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== "granted") {
alert("Failed to get push token for push notification!");
return;
}
token = (await Notifications.getExpoPushTokenAsync()).data;
}
if (Platform.OS === "android") {
Notifications.setNotificationChannelAsync("default", {
name: "default",
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: "#FF231F7C",
});
}
return token;
}
effect from App.js
useEffect(() => {
initFirebaseApp();
registerForPushNotificationsAsync().then(async (token) => {
//store in some place token
});
// This listener is fired whenever a notification is received while the app is foregrounded
notificationListener.current =
Notifications.addNotificationReceivedListener(handleNotification);
// This listener is fired whenever a user taps on or interacts with a notification (works when app is foregrounded, backgrounded, or killed)
responseListener.current =
Notifications.addNotificationResponseReceivedListener(
handleNotificationResponse
);
return () => {
Notifications.removeNotificationSubscription(
notificationListener.current
);
Notifications.removeNotificationSubscription(responseListener.current);
};
}, []);
notification handlers in App.js
const handleNotification = (response) => {
// console.log(response);
};
const handleNotificationResponse = (response) => {
// console.log(response)
};
I hope this helps you
Docs
Expo SDK documentation
Expo docs reference
I am trying to read blockchain event (in Java) using web3j but getting NPE:
java.lang.NullPointerException: null
at org.web3j.protocol.core.filters.LogFilter.process(LogFilter.java:46)
at org.web3j.protocol.core.filters.Filter.getInitialFilterLogs(Filter.java:119)
at org.web3j.protocol.core.filters.Filter.run(Filter.java:69)
at org.web3j.protocol.rx.JsonRpc2_0Rx.run(JsonRpc2_0Rx.java:89)
at org.web3j.protocol.rx.JsonRpc2_0Rx.lambda$ethLogFlowable$2(JsonRpc2_0Rx.java:79)
at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:71)
at io.reactivex.Flowable.subscribe(Flowable.java:14935)
at io.reactivex.Flowable.subscribe(Flowable.java:14872)
at io.reactivex.Flowable.subscribe(Flowable.java:14791)
Code in question
for (EthLog.LogResult logResult : logResults) {
https://github.com/web3j/web3j/blob/master/core/src/main/java/org/web3j/protocol/core/filters/LogFilter.java#L46
#Override
protected void process(List<EthLog.LogResult> logResults) {
for (EthLog.LogResult logResult : logResults) {
if (logResult instanceof EthLog.LogObject) {
Log log = ((EthLog.LogObject) logResult).get();
callback.onEvent(log);
} else {
throw new FilterException(
"Unexpected result type: " + logResult.get() + " required LogObject");
}
}
}
Raised issue https://github.com/web3j/web3j/issues/1486
But as not expected that to be fixed, what should I do?
Sample code and/or code snippets
private void createEventMonitor() {
log.info("createEventMonitor() begin...");
// contract from block
EthFilter filter = new EthFilter(DefaultBlockParameter.valueOf(new BigInteger("7605105")),
DefaultBlockParameterName.LATEST, contractAddress);
//Disposable subscription
subscription = web3j
.ethLogFlowable(filter)
.subscribe(
event -> {
log.info("Withdraw event received:");
log.info(" event data >>> {}", event.getData());
log.info(" event topic >>> {}", event.getTopics().stream().collect(Collectors.joining()));
log.info(" event address >>> {}", event.getAddress());
log.info(" event txHash >>> {}", event.getTransactionHash());
}, error -> {
log.error("Event error: {}", error, error); //!
});
log.info("createEventMonitor() end.");
}
This error should go away in the future after https://github.com/web3j/web3j/pull/1495 solving https://github.com/web3j/web3j/issues/1486 (should be next version after 4.8.7)
In short: JSON RPC error was no visible on web3j level.
To analyze issue like that run program with log level debug to see JSON RPC messages.
I am unable to persist an entity using ManagedExecutor in Quarkus.
managedExecutor.runAsync(() -> {
User user = User.findById(userId);
if (user == null) {
return;
}
BigDecimal amount;
try {
amount = new BigDecimal(split[1]);
} catch (NumberFormatException e) {
throw new BadRequestException("Invalid amount: " + split[1] + ", " + e.getMessage());
}
managedExecutor.runAsync(threadContext.contextualRunnable(new Runnable() {
#Override
#Transactional
#ActivateRequestContext
public void run() {
user.minimumAmount = amount;
user.persistAndFlush();
}
}));
sendMessage(userId, new NewMinimumAmountMessage(user.minimumAmount));
});
Right now there are no exceptions thrown and nothing after persistAndFlush() gets executed.
I have tried to put the persist in the initial runAsync but that also doesn't work.
The code here is in a websocket function which is annotated with #OnMessage, putting #Transactional here doesn't do anything.
Both the ManagedExecutor and the ThreadContext are injected.
I was able to fix it but I know it's not the proper way.
Response response = given()
.auth().oauth2(token)
.header("Bearer", token)
.header("Content-Type", "application/json")
.when().put("/api/user/amount/" + split[1])
.thenReturn();
I added a path in a resource and used the test function to call it.