I am working on an java application that will makes calls to a web service, I dont want to incur additional latency while making these calls hence I am planning on doing this asynchronously. Using threads is one way to go about it but this approach might become unreliable if the calls to the dependent service fail because of various reasons. So essentially what I am looking is some kind of in-process asynchronous service will fallback to temporarily store (inprocess database ?) and retry the failed requests. Are there are any exiting solutions out there that achieve this ? If not it would help if someone could point me to something that does a similar task like this.
Thanks
Actually, I've not yet tried it, but Reactor is something like Node.js and should allow you to program using event-driven paradigm.
Please check it out and let us know if it suits your needs.
Quarkus has easy built in reactive asynchronous call processing.
Like:
#ApplicationScoped
#RegisterForReflection
#Path("/")
public class JokesServiceCallManager {
private static final Logger LOGGER =
LoggerFactory.getLogger(JokesServiceCallManager.class);
#Inject
JokeResponseHandler jokeResponseHandler;
#Inject
JokeSetupAdapter jokesSetupAdapter;
#Inject
JokeReactionAdapter jokesReactionAdapter;
public Uni<Response> getData(String id,String correlationId) {
LOGGER.debug("********** getData(String id) id = " + id);
Uni<Response> uniSetup = jokesSetupAdapter.getByIdAsync(id);
Uni<Response> uniReaction =
jokesReactionAdapter.getByIdAsync(id);
return Uni.combine().all().unis(uniSetup, uniReaction )
.asTuple().onItem().transformToUni(tuple ->
jokeResponseHandler.createUniResponse(tuple.getItem1(),
tuple.getItem2()));
// .onFailure().invoke(exception ->
jokeResponseHandler.buildUniExceptionResponse(exception));
}
Which returns a tuple of all the calls when complete.
Simply allowing the service return to be cast to an Uni makes it all reactive (non-blocking)
The calls are as simple as :
import javax.ws.rs.core.Response;
import
org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.smallrye.mutiny.Uni;
#RegisterRestClient(configKey="setup-api")
#RegisterClientHeaders(SetupHeaderFactory.class)
public interface JokesSetupService {
#GET
#Path("/jokesetup/{id}")
#Produces(MediaType.APPLICATION_JSON)
Uni<Response> getByIdAsync(#PathParam("id") String id);
}
Related
I'm developing a SpringBoot web application for managing gaming servers.
I want to have a cronjob that queries the servers, checks whether they have crashed and collects relevant data, such as the number of players online etc. This data needs to be stored and shared among services that require it. Since this data will change often and will become invalid after the whole application stops, I don't want to persist these stats in the database, but in the application memory.
Current implementation
Currently, my implementation is pretty naive - having a collection as a member field of the corresponding Spring service and storing the server statuses there. However I feel this is a really bad solution, as the services should be stateless and also I don't take concurrency into account.
Example code:
#Service
public class ServersServiceImpl implements ServersService {
private final Map<Long, ServerStats> stats = new HashMap<>(); // Map server ID -> stats
...
public void startServer(Long id) {
// ... call service to actually start server process
serverStats.setRunning(true);
stats.put(id, serverStats);
}
...
}
Alternative: Using #Repository classes
I could move the collection with the data to classes with #Repository annotation, which would be semantically more correct. There, I would implement a thread-safe logic of storing the data in java collection. Then I would inject this repository into relevant services.
#Repository
public class ServerStatsRepository {
private final Map<Long, ServerStats> stats = new ConcurrentHashMap<>();
...
public ServerStats getServerStats(Long id) {
return stats.get(id);
}
public ServerStats updateServerStats(Long id, ServerStats serverStats) {
return stats.put(id, serverStats);
}
...
}
Using Redis also came to mind, but I don't want to add too much complexity to the app.
Is my proposed solution a valid approach? Would there be any better option of handling this problem?
I am using web flux in my project and am trying to do simple CRUD operations using JPA repository. However I' unable to persist the object in the DB. The object is always being persisted with null values instead in the DB. Please help. Thanks in advance.
Here is my pojo:
#Entity
#Table(name="tbl_student")
#Data
public class Student {
#Id
#GeneratedValue(strategy= GenerationType.SEQUENCE,generator = "student_seq")
#SequenceGenerator(name="student_seq",allocationSize = 1)
#Column(name="id",insertable =false,nullable = false,updatable = false)
private Long id;
#Column(name="name")
private String name;
#Column(name="school")
private String school;
}
My Repo:
public interface StudentRepository extends JpaRepository<Student,Long> {
}
My controller:
#RestController
#RequiredArgsConstructor
#Slf4j
public class StudentApiControllerImpl extends StudentApiController {
private final StudentRepository StudentRepository;
private final ModelMapper modelMapper;
public Mono<Void> addStudent(#Valid #RequestBody(required = false) Mono<StudentDetails> studentDetails, ServerWebExchange exchange) {
StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class));
return Mono.empty();
}
public Flux<StudentDetails> getStudent(ServerWebExchange exchange) {
return Flux.fromStream(StudentRepository.findAll().stream().map(v ->
modelMapper.map(v,LoginCredential.class))).subscribeOn(Schedulers.boundedElastic());
}
}
You are breaking the reactive chain, thats why nothing happens.
Reactive programming is a lot different than standard java programming so you can't just do what you have done before and think that it will work the same.
In reactive programming one of the most important things to understand is nothing happens until you subscribe
A reactive chain is build by a producer and a subscriber which means someone produces (your application) and someone subscribes (the calling client/application). A Flux/Mono is a producer and nothing will happen until someone subscribes.
// Nothing happens, this is just a declaration
Mono.just("Foobar");
But when we subscribe:
// This will print FooBar
Mono.just("Foobar").subscribe(s -> System.out.println(s));
So if we look at your code, especially this line
// This is just a declaration, no one is subscribing, so nothing will happen
StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class));
A common misconception is that people will solve this by just subscribing.
// This is in most cases wrong
StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class)).subscribe();
Because the subscriber is the calling client, the one that initiated the call. Doing as such might lead to very bad performance under heavier loads. Instead what you do is that you need to return the Mono out to the client, so that the client can subscribe.
public Mono<Void> addStudent(#Valid #RequestBody(required = false) Mono<StudentDetails> studentDetails, ServerWebExchange exchange) {
return StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class))
.then();
}
I am using Mono#then here to throw away the return value and just return a void value to the calling client.
But as you can see, you need to think about it like callbacks, you need to always return so it will build a chain that gets returned to the calling client, so that the client can subscribe.
I highly suggest you read the reactive documentation so you understand the core concepts before starting out with reactive programming.
Reactive programming getting started
Also, another thing, you can not use JpaRepository in a reactive world because it is using a blocking database driver. Which means basically it is not written to work well with Webflux and will give very poor performance. If you want to use a database connection i suggest you look into using R2DBC by spring here is a tutuorial to get it up and running R2DBC getting started
Update:
i see now that you have placed the entire call on its own scheduler which is good since you are using JPA and that will result in less bad performance. But i do recommend still, if possible, to look into using R2DBC for a fully reactive application.
Also, if you insist on using JPA with a blocking database driver, you need to perform your call in a reactive context, since it will return a concrete value. So for instance:
return Mono.fromCallable(() -> StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class)))
.then()
Which means we are basically executing our function and immediately placing the returned type into a Mono, and then as the above example using Mono#then to discard the return value and just signal that the execution has completed.
I am trying to get Json String from Mono. I tried to use block() method to get object it worked fine , but when I use map/flatmap ,I don't see following lines of code is executed.And I see account Mono is not empty.
private String getJsonString( Mono<Account> account) {
response.map(it->{
**// call is not coming here**
val json = mapper.writeValueAsString(it)
System.out.println(son)
});
}
am I doing anything wrong here?
If you give a read to the official documentation , you will see that:
Nothing happens until you subscribe
Now to understand, In spring boot webflux based microservice, who is the subscriber?, have a look at this stackoverflow question
Now, if you think, you can have blocking and reactive implementations in the same service, unfortunately, it doesn't work like that. For this you have to understand the event loop model on which reactor works. Thus calling a block method at any point in the flow is of no good and is equivalent to using the old blocking spring-web methods. Because the thread in which the request is being processed gets blocked and waits for the outcome of the I/O operation / network call.
Coming to your question in the comment:
But when i use flatMap in my controller to call handler method it goes service method with Object not mono?serviceRequest-->Mono-->Object how this works?
Let me give you a simple example for this:
Suppose you have an employee application, where you want to fetch details of an employee for a given id.
Now in your controller, you will have an endpoint like this:
#GetMapping("/{tenant}/api/employee/{id}")
public Mono<ResponseEntity> getEmployeeDetails(#PathVariable("id") Long employeeId) {
return employeeService.getDetails(employeeId)
.map(ResponseEntity::ok);
}
Now in your service,
public Mono<EmployeeEntity> getDetails(Long employeeId) {
return employeeRepository.findById(employeeId);
}
And your repository will look like this:
#Repository
public interface EmployeeRepository extends ReactiveCrudRepository<EmployeeEntity, Long> {
}
I don't want to perform a blocking operation.
Caused by: java.lang.IllegalStateException: You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread.
Anyone know how to fix this problem?
I only have simple operations. a single findAll request that returns 10 rows. I put Tansactional NEVER
and I still have the problem.
I'm using panache with a simple entity.
#GET
#Path("/type")
#Produces(MediaType.APPLICATION_JSON)
#Transactional(Transactional.TxType.NEVER)
public Response get() {
return AlertType.listAll();
}
public class AlerteType extends PanacheEntityBase
{
#Column(name="ATY_ACTIVE")
private String active;
#Column(name="ATY_ID")
#Id
private Long oraId;
#Column(name="ATY_TYPE")
private String type;
}
thank
If you want to keep using non-reactive code, you can use #Blocking annotation on the method get(). It will offload the computation on a worker thread (instead of one IO thread).
Quarkus is really picky with IO thread, you cannot block them. And if you have something like a database call (or any remote call), that is blocking. So you cannot do it in an IO thread.
More info:
https://quarkus.io/guides/getting-started-reactive
https://quarkus.io/blog/resteasy-reactive-faq/
"Controller" methods (request / route / path handlers, or whatever you call it) is executed on IO thread and not supposed to do any time consuming tasks such as database querying.
If you're not using reactive database client, try wrap them in side a "Service" class.
#ApplicationScoped
public class AlertService {
private final AlertType alertType;
#Inject
public AlertService(AlertType alertType) {
this.alertType = alertType;
}
public List<Alert> listAll() {
return this.alertType.listAll();
}
}
thank you but I already had the call in a service.
I found a solution with mutiny
#GET
#Path("type")
#Produces(MediaType.APPLICATION_JSON)
public Uni<Response> get() {
return Uni.createFrom().item(alertTypeService.findAll().get())
.onItem().transform(data -> Response.ok(data))
.onFailure().recoverWithItem(err -> Response.status(600, err.getMessage()))
.onItem().transform(ResponseBuilder::build)
.emitOn(Infrastructure.getDefaultExecutor())
}
Where alertTypeService.findAll() return a supplier
#Transactional(Transactional.TxType.NEVER)
public Supplier<Set<AlerteTypeDTO>> findAll() {
return () -> alerteTypeDAO.streamAll()
.map(AlertTypeDTOMapper::mapToDTO)
.collect(Collectors.toSet());
}
I don't know if this is the right solution
but it works.
This way the service provides a supplier which will be invoked by the correct thread.
At least that's how I understood it.
I'm having a very hard time understanding Akka's integration with the Play framework. I'd like to integrate Akka actors into a non controller library class of my own creation, but the documentation only provides an example in a controller returning a Result (Play 2.3). I don't have any code written yet because I'm so vexed on how to move forward. Does anyone have any examples on the proper usage of Akka outside a controller? I found this example (Java 8):
import play.libs.F.Promise;
import play.mvc.*;
import static play.libs.F.Promise.promise;
public class Application extends Controller {
public static Promise<Result> index() {
return promise(() -> longComputation())
.map((Integer i) -> ok("Got " + i));
}
}
but it looks like it has nothing to do with Akka at all. I'm so stumped I'm not even sure if I'm asking this question right, and I apologize for not having code samples.
My assumption is this: Place the above code sample in my library class and use it as specified, treating the "longRunningComputation()" as I would any other method call, and leave it at that. My concern at that point is that I'm not really leveraging what Akka has to offer.
Is there an Akka tutorial anyone would recommend to help here?
Overall
Please keep in mind that Akka is (practically) in no way related or restricted to Play. There are thousands of systems built on top of Akka which have nothing to do with Play. Akka and Play just play well together.
Akka + Play
It is perfectly fine to use Akka actors in the non-controller part of your application. You would just need a way to connect your controller to your actor system. This means you would need to find a way to talk to the actors in your actor system. There are (in general) two ways to do this in Akka. You either say (send) something to the actor or you ask him something.
tell
Saying / sending (also known as telling or fire-and-forget) is done in Java with actor.tell(message, getSelf()) and in Scala with actor ! message
import akka.actor.*;
import play.mvc.*;
import play.libs.Akka;
import play.libs.F.Promise;
import static akka.pattern.Patterns.ask;
public class Application extends Controller {
public static Result index() {
// select some actor from your system
ActorSelection actor = Akka.system().actorSelection("user/my-actor");
// now tell the actor something and do something else because we don't get a reply
actor.tell("Something");
return ok("Hello");
}
}
Of course you are in no way limited to contact the actor only from your controller's methods.
The whole process messaging process can be of course very complex - it totally depends on your business logic. The actor my-actor from above will now receive the message and do lots of stuff at this point - forward it, spawn children, kill itself, do calculations, etc.
In Java you will have an actor like:
import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;
public class MyUntypedActor extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
log.info("Received String message: {}", message);
// do whatever you want with this String message
} else
unhandled(message);
}
}
ask
Asking is done with ... surprise .. the ask pattern - in Scala with actor ? message.
You already have found an example how to do it in Java. Please keep in mind that this time you get something back. This is the so-called Future. Once this future completes (successfully) you will have your result. Then you can map this result to some other result. See now why the map() call is there?
import akka.actor.*;
import play.mvc.*;
import play.libs.Akka;
import play.libs.F.Promise;
import static akka.pattern.Patterns.ask;
public class Application extends Controller {
public static Promise<Result> index() {
// select some actor from your system
ActorSelection actor = Akka.system().actorSelection("user/my-actor");
// now ask the actor something and do something with the reply
return Promise.wrap(ask(actor, "how are you?", 1000))
.map(response -> ok(response.toString()));
}
}
Some notes from personal experience:
the Akka documentation is your friend
take a look at the WebSocket connections use cases - build yourself a demo Play app where you support WebSocket and every connection is handled by an actor. Now think of a chat application - once I send something on the WebSocket, I would like that every other user of the app receives it - now this is fine case for "hello-world-Akka actors", isn't it