I am using RxJava for a server microservice project, where using Jetty as HTTP Servlet server.
I am handling requests either from client or main server with Observable for different flows.
When a request hitting the api below, I will return a Response after Observable finishes the job.
#GET
#Path("{uuid}")
#Produces(MediaType.APPLICATION_JSON)
public Response doThingsForClient(#PathParam("uuid") String uuid) {
Worker worker = new Worker(uuid);
worker.run();
return Response.ok("Awesome").build();
}
class Worker {
String uuid = null;
public Worker(String uuid) {
this.uuid = uuid;
}
public void run() {
Observable.concat(Observable1,Observable2,Observable3);
}
}
I am wondering if I need to dispose these Observables or Flowables.
According to this: Does RxJava2 auto dispose observable when they call completed or error?
and the RxJava3 sourcecode, i don't think Flowable at least is disposed automatically?
If I need to manually dispose the resources,
Is it better to create a CompositeDisposable, then add disposable to the CompositeDisposable at each Observer(Observable1...Observable3)'s onSubscribe() being called, call compositeDisposable.dispose() after the concat finishes.
Should I also monitor the Jetty AbstractLifeCycle to dispose these Observables(It sounds similar as Android)? I am not sure how other people are using RxJava at the server side, open to any suggestions to these questions and general Rx approach at server projects.
Thanks!
Related
I am looking at some examples of reactive web applications and i am seeing them like this
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
#ResponseBody
public Mono<Person> findById(...) {
return exampleService.findById(...);
}
#RequestMapping(method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
#ResponseBody
public Flux<Person> findAll() {
Flux<Person> persons = exampleService.findAll();
return persons;
}
When i am reading about the Mono and Flux in the documentation it mentioned subscribe has to be called for Mono or Flux to emit the data.
So when i run these reactive webapplications locally and using postman/chrome browser when i hit the endpoints i getting the results.
On the service side though endpoints are returning Mono or Flux, how i am seeing the actual results in the browser/postman.
Is the browser doing the part of calling the subscribe internally whenever i am hitting the endpoints that return Mono/Flux types?
Mono and Flux concepts exist only within your application, while HTTP protocol is used to communicate between your postman/chrome app and your application.
Internal classes of the Spring Webflux framework subscribe to Mono and Flux instances returned by your controller methods and map them to HTTP packets based on the MediaType that you specified in RequestMapping.
It depends on which server you use.
For instance, Tomcat, Jetty (Servlet 3.1 non-blocking I/O) - ServletHttpHandlerAdapter from org.springframework.http.server.reactive package.
Subscription happens in service method:
#Override
public void service(ServletRequest request, ServletResponse response) throws
ServletException, IOException {
...
HandlerResultSubscriber subscriber = new HandlerResultSubscriber(asyncContext,
isCompleted, httpRequest);
this.httpHandler.handle(httpRequest, httpResponse).subscribe(subscriber);
}
So I am writing REST Service in which I want to return JMS answer from queue.
Everythink looks like this:
#Controller
#RequestMapping("/rest")
public class UserService {
#Autowired
JMSProducer jmsproducer;
#RequestMapping(value="/users", method=RequestMethod.GET)
public String getUsers(){
return jmsproducer.send();
}
}
Method send() send message to queue to BACKEND ( backend have connection to DataBase ) then backend send in queue message all users to my rest and then my JMSProducer class with method onMessage from MessageListener receive sended message. (using MessageProducer's and MessageConsumer's)
Question is: How can i receive this all users from queue on this method getUsers because onMessage function is void type.
Please help me, i don't have any idea how to do that in a good way.
I am using ActiveMQ.
What is best way to attempt multiple time same RPC call while failing RPC call?
just example: Here one case like if RPC get failed due to network connection, it will catch in onFailure(Throwable caught).
Now here it should recall same RPC again for check network connection. The maximum attempt should be 3 times only then show message to user like "Network is not established"
How can I achieve it?
Some couple of thoughts like call same rpc call in onFailure but here request become different.but I want same request have a three request and it is not good approach and I don't know if any good solution for it.
Thanks In Advance.
Use a counter in your AsynCallBack implementation. I recommend as well to use a timer before requesting the server again.
This code should work:
final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
final String textToServer = "foo";
greetingService.greetServer(textToServer, new AsyncCallback<String>() {
int tries = 0;
public void onSuccess(String result) {
// Do something
}
public void onFailure(Throwable caught) {
if (tries ++ < 3) {
// Optional Enclose the new call in a timer to wait sometime before requesting the server again
new Timer() {
public void run() {
greetingService.greetServer(textToServer, this);
}
}.schedule(4000);
}
}
});
#Jens given this answer from Google Groups.
You could transparently handle this for all your requests of a given GWT-RPC interface by using a custom RpcRequestBuilder. This custom RpcRequestBuilder would make 3 request attempts and if all 3 fail, calls the onFailure() method.
MyRemoteServiceAsync service = GWT.create(MyRemoteService.class);
((ServiceDefTarget) service).setRpcRequestBuilder(new RetryThreeTimesRequestBuilder());
The custom RequestBuilder could also fire a "NetworkFailureEvent" on the eventBus if multiple application components may be interested in that information. For example you could overlay the whole app with a dark screen and periodically try sending Ping requests to your server until network comes back online. There is also the onLine HTML 5 property you can check, but its not 100% reliable (https://developer.mozilla.org/en-US/docs/Web/API/window.navigator.onLine)
I’m having a problem processing Subscription Requests from Clients and carrying out some processing based on the request. I’d like to be able to invoke a method and carry out some processing when an incoming subscription request is received on the Server. I’ve had a look at the following CometD documentation and tried the example outlined in “Subscription Configuration Support” but I’m not having much luck.
http://www.cometd.org/documentation/2.x/cometd-java/server/services/annotated
I’ve already created the Bayeux Server using a Spring Bean and I’m able to publish data to other channel names I’ve created on the Server side. Any help or additional info. on the topic would be appreciated!
The code example I’m using:
#Service("CometDSubscriptionListener")
public class CometDSubscriptionListener {
private final String channel = "/subscription";
private static final Logger logger = Logger.getLogger(CometDSubscriptionListener.class);
private Heartbeat heartbeat;
#Inject
private BayeuxServer bayeuxserver;
#Session
private ServerSession sender;
public CometDSubscriptionListener(BayeuxServer bayeuxserver){
logger.info("CometDSubscriptionListener constructor called");
}
#Subscription(channel)
public void processClientRequest(Message message)
{
logger.info("Received request from client for channel " + channel);
PublishData();
}
Have a look at the documentation for annotated services, and also to the CometD concepts.
If I read your question correctly, you want to be able to perform some logic when clients subscribe to a channel, not when messages arrive to that channel.
You're confusing the meaning of the #Subscription annotation, so read the links above that should clarify its semantic.
To do what I understood you want to do it, you need this:
#Service
public class CometDSubscriptionListener
{
...
#Listener(Channel.META_SUBSCRIBE)
public void processSubscription(ServerSession remote, ServerMessage message)
{
// What channel the client wants to subscribe to ?
String channel = (String)message.get(Message.SUBSCRIPTION_FIELD);
// Do your logic here
}
}
I have a problem with streams and the web api.
I return the stream which is consumed by the web api. Currently, i put the socket into a pool after getting the stream. but this cause some errors.
Now, I must putthe socket into the pool AFTER the request ended. (The stream was consumed and is now closed).
Is there a delegate for this or some other best practises?
Example code:
public HttpResponseMessage Get(int fileId)
{
HttpResponseMessage response = null;
response = new HttpResponseMessage(HttpStatusCode.OK);
Stream s = GetFile(id);
response.Content = new StreamContent(fileStream);
}
GetFile(int id)
{
FSClient fs = GetFSClient();
Stream s = fs.GetFileStream(id);
AddFSToPool(fs);
return s;
}
GetFile uses a self-programmed FileServer-Client.
It has an option to reuse FileServer-Connections. This connections will be stored in a pool. (In the pool are only unused FileServer-connections). If the next request calls GetFSClient() it gets an connected one from the pool (and removes it from the pool).
But if another requests comes in and uses a FileServer-Connection which is in the pool (because unused), there is still the problem, that the Stream is possibly in use.
Now I want to do the "put the FSClint into the pool" after the request ended and the stream is fully consumed.
Is there an entry point for that?
Stream is seen as a volatile/temporary resource - no wonder it implements IDisposable.
Also Stream is not thread-safe since it has a Position which means if it is read up to the end, it should be reset back to start and if two Threads reading the stream they will most likely read different chunks.
As such, I would not even attempt to solve this problem. Re-using streams on a web site (inherently multi-user / multi-threaded) not recommended.
UPDATE
As I said, still think that the best option is to re-think the solution but if you need to register something that runs after request finishes, use RegisterForDispose on request:
public HttpResponseMessage Get(HttpRequestMessage req, int fileId)
{
....
req.RegisterForDispose(myStream);
}