I have some basic project that has like four calls to some external resource, that in current version runs synchronously. What I would like to achieve is to wrap that calls into HystrixObservableCommand and then call it asynchronously.
From what I have read, after calling .observe() at the HystrixObservableCommand object, the wrapped logic should be called immediately and asynchronously. However I am doing something wrong, because it works synchronously.
In the example code, the output is Void, because I'm not interested in output (for now). That is also why I did not assigned the Observable to any object, just called constructor.observe().
#Component
public class LoggerProducer {
private static final Logger LOGGER = Logger.getLogger(LoggerProducer.class);
#Autowired
SimpMessagingTemplate template;
private void push(Iterable<Message> messages, String topic) throws Exception {
template.convertAndSend("/messages/"+topic, messages);
}
public void splitAndPush(Iterable<Message> messages) {
Map<MessageTypeEnum, List<Message>> groupByMessageType = StreamSupport.stream(messages.spliterator(), true)
.collect(Collectors.groupingBy(Message::getType));
//should be async - it's not
new CommandPushToBrowser(groupByMessageType.get(MessageTypeEnum.INFO),
MessageTypeEnum.INFO.toString().toLowerCase()).observe();
new CommandPushToBrowser(groupByMessageType.get(MessageTypeEnum.WARN),
MessageTypeEnum.WARN.toString().toLowerCase()).observe();
new CommandPushToBrowser(groupByMessageType.get(MessageTypeEnum.ERROR),
MessageTypeEnum.ERROR.toString().toLowerCase()).observe();
}
class CommandPushToBrowser extends HystrixObservableCommand<Void> {
private Iterable<Message> messages;
private String messageTypeName;
public CommandPushToBrowser(Iterable<Message> messages, String messageTypeName) {
super(HystrixCommandGroupKey.Factory.asKey("Messages"));
this.messageTypeName = messageTypeName;
this.messages = messages;
}
#Override
protected Observable<Void> construct() {
return Observable.create(new Observable.OnSubscribe<Void>() {
#Override
public void call(Subscriber<? super Void> observer) {
try {
for (int i = 0 ; i < 50 ; i ++ ) {
LOGGER.info("Count: " + i + " messageType " + messageTypeName);
}
if (null != messages) {
push(messages, messageTypeName);
LOGGER.info("Message type: " + messageTypeName + " pushed: " + messages);
}
if (!observer.isUnsubscribed()) {
observer.onCompleted();
}
} catch (Exception e) {
e.printStackTrace();
observer.onError(e);
}
}
});
}
}
}
There are some pure "test" code fragments there, as I was trying to figure out the problem, just ignore the logic, main focus is to make it run async with .observe(). I do know that I may achieve that with standard HystrixCommand, but this is not the goal.
Hope someone helps :)
Regards,
Answer was found:
"Observables do not add concurrency automatically. If you are modeling
synchronous, blocking execution with an Observable, then they will
execute synchronously.
You can easily make it asynchronous by scheduling on a thread using
subscribeOn(Schedulers.io()). Here is a simply example for wrapping a
blocking call with an Observable:
https://speakerdeck.com/benjchristensen/applying-reactive-programming-with-rxjava-at-goto-chicago-2015?slide=33
However, if you are wrapping blocking calls, you should just stick
with using HystrixCommand as that’s what it’s built for and it
defaults to running everything in a separate thread. Using
HystrixCommand.observe() will give you the concurrent, async
composition you’re looking for.
HystrixObservableCommand is intended for wrapping around async,
non-blocking Observables that don’t need extra threads."
-- Ben Christensen - Netflix Edge Engineering
Source: https://groups.google.com/forum/#!topic/hystrixoss/g7ZLIudE8Rs
Related
Could somebody help me to do the following:
#PostContruct public void func() {
webclient.get()...subscribe();
}
webclient call will terminate after func() returns. Most likely it will happen before the first request comes in, but no guarantees. The other option is to block(), which defeats the purpose of being reactive.
What would be the right way to make reactive calls in #PostConstruct methods?
Thank you.
I created a simple bean.
Synchronous update:
#Component
public class BeanTest {
private String postConstructValue;
#PostConstruct
public void init(){
try {
Thread.sleep(5000);
this.postConstructValue = "Construction done";
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Scheduled(fixedRate = 500)
public void print(){
System.out.println(
this.postConstructValue
);
}
}
It took some time for app to start (more than 5 seconds) because we simulated some time consuming process in the post construct. Scheduled print method started printing only after the app started. It started printing "Construction done" message.
Asynchronous update:
#Component
public class BeanTest {
private String postConstructValue;
#PostConstruct
public void init(){
Flux.just("Construction done")
.delayElements(Duration.ofSeconds(5))
.subscribe(s -> this.postConstructValue = s);
}
#Scheduled(fixedRate = 500)
public void print(){
System.out.println(
this.postConstructValue
);
}
}
Now in this approach, the app started within 2 seconds. Print method starting printing null for few seconds. Then it started printing "Construction done". It does not terminate the Flux postConstruct value update. It happened asynchronously.
Reactive approach is good when you want a non-blocking behavior and getting something done asynchronously. If you think that your component creation should wait for proper construction, you have to block! Otherwise, you can go with second approach.
I need to use actions and actors for CRUD logic in my application. I am following an architecture document that defines an action as being the synchronous part and the actor as being the asynchronous part, which makes sense. However, the actor, which writes data back to a file, only needs to do its own operations if an action has completed successfully. For example, if an entry is successfully updated, then write the data back. If the entry was not successfully updated, then don't write the data back. I was thinking of calling action.execute in an execute() function in an actor:
public void execute() {
if(action.execute()) {
executeAsynchronously();
}
}
However, this seems like it doesn't really fit in with the actor model. As more background I have a manager class that manages all the entries and data. There are add(), delete(), and update() methods in that class that each do:
public void addEntry(UserkEntry entryModel, boolean notify) {
assert entryModel != null;
synchronized (this) {
AddEntryAction action = new AddEntryAction();
UserDirectoryActor actor = new UserDirectoryActor(action);
addActor(actor);
actor.execute();
}
}
And my method to add an actor:
protected final synchronized void addActor(UserDirectoryActor actor) throws BusinessException {
for(UserDirectoryActor act : actors) {
if(act.equals(actor)) {
UserServiceFw.log.error("Actor for " + act.getAction() + " already exists");
throw new BusinessException("UserDirectoryActor could not be added for: " + act.getAction());
}
}
actors.add(actor);
}
How can I modify my code to better fit the actor model? And is the synchronization overkill?
In a loop i need to make some checks, performed actually in some another verticle. In each iteration of my loop i need to check the response code, returned from those verticle and make some decision accordingly. In some other words i need to stop the execution of my loop and somehow wait till asynch. call returns. But such execution stop violates the vert.x philosophy, which states that main thread execution should be never stopped. How can i do it in the scope of Vert.x? So far i don't know how to do this. Any suggestions/code samples/urls to smth. like a solution would b highly appreciated.
Thanks!
When working with Vert.x you need to think less in terms of loops, and more in terms of callbacks.
You should use eventBus to communicate between vertices.
Let's say that what you want is something similar to this pseudocode:
for (int i = 0; i < 4; i++) {
int result = getVerticleResult();
System.out.println(result);
}
So, just a very basic example
class LooperVerticle extends AbstractVerticle {
private int i = 4;
#Override
public void start() throws Exception {
doWork();
}
private void doWork() {
vertx.eventBus().send("channel", "", (o) -> {
if (o.succeeded()) {
System.out.println(o.result().body());
i--;
if (i > 0) {
doWork();
}
}
});
}
}
class WorkerVerticle extends AbstractVerticle {
#Override
public void start() throws Exception {
vertx.eventBus().consumer("channel", (o) -> {
// Generate some random number
int num = ThreadLocalRandom.current().nextInt(0, 9);
// Simulate slowness
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
o.reply(num);
});
}
}
To test:
public class EventBusExample {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new LooperVerticle());
vertx.deployVerticle(new WorkerVerticle());
}
}
I think you need to use FutureTask and store them in a Collection and use FutureTask.get() to retrieve the result when needed which is a blocking call.
It sounds like a use case for reactive steam processing.
In general such problem could be solved using 2 parties:
a producer that executes tasks and returns asynchronous results
a handler that subscribes to results and performs another tasks
There is a way to configure producer to perform tasks only when there is a subscriber. And on other side subscriber can decide to unsubscribe from producer on some condition.
I'm not familiar with vertx capabilities for reactive streams. But I would start from RxJava integration
http://vertx.io/docs/vertx-rx/java/
I've been looking for hints on how to best test Spring MVC Controller methods that return SseEmitters. I have come up pretty short, but have a trial-and-error solution that tests against asynchronous, threaded behavior. The below is sample code just to demonstrate concept, there may be a typo or two:
Controller Class:
#Autowired
Publisher<MyResponse> responsePublisher;
#RequestMapping("/mypath")
public SseEmitter index() throws IOException {
SseEmitter emitter = new SseEmitter();
Observable<MyResponse> responseObservable = RxReactiveStreams.toObservable(responsePublisher);
responseObservable.subscribe(
response -> {
try {
emitter.send(response);
} catch (IOException ex) {
emitter.completeWithError(ex);
}
},
error -> {
emitter.completeWithError(error);
},
emitter::complete
);
return emitter;
}
Test Class:
//A threaded dummy publisher to demonstrate async properties.
//Sends 2 responses with a 250ms pause in between.
protected static class MockPublisher implements Publisher<MyResponse> {
#Override
public void subscribe(Subscriber<? super MyResponse> subscriber) {
new Thread() {
#Override
public void run() {
try {
subscriber.onNext(response1);
Thread.sleep(250);
subscriber.onNext(response2);
} catch (InterruptedException ex) {
}
subscriber.onComplete();
}
}.start();
}
}
//Assume #Configuration that autowires the above mock publisher in the controller.
//Tests the output of the controller method.
#Test
public void testSseEmitter() throws Exception {
String path = "http://localhost/mypath/";
String expectedContent = "data:" + response1.toString() + "\n\n" +
"data:" + response2.toString() + "\n\n");
//Trial-and-Error attempts at testing this SseEmitter mechanism have yielded the following:
//- Returning an SseEmitter triggers 'asyncStarted'
//- Calling 'asyncResult' forces the test to wait for the process to complete
//- However, there is no actual 'asyncResult' to test. Instead, the content is checked for the published data.
mockMvc.perform(get(path).contentType(MediaType.ALL))
.andExpect(status().isOk())
.andExpect(request().asyncStarted())
.andExpect(request().asyncResult(nullValue()))
.andExpect(header().string("Content-Type", "text/event-stream"))
.andExpect(content().string(expectedContent))
}
As noted in the comments, asyncResult() is called to ensure that the publisher finishes its work and sends both responses before the test completes. Without it, the content check fails due to only one response being present in the content. However there is no actual result to check, hence asyncResult is null.
My specific question is whether there is a better, more precise way to force the test to wait for the async process to finish, rather than the klugie method here of waiting for a non-existent asyncResult. My broader question is whether there are other libs or Spring methods that are better suited to this vs. these async functions. Thanks!
This is a more general answer as it is meant to test an SseEmitter that will run forever, but will disconnect from SSE stream after a given timeout.
As for a different approach than MVC, as #ErinDrummond commented to the OP, you might want to investigate WebFlux.
It is a minimal example. One might want to expand with headers to the request, different matchers or maybe work on the stream output separately.
It is setting a delayed thread for disconnecting from SSE Stream which will allow to perform assertions.
#Autowired
MockMvc mockMvc;
#Test
public void testSseEmitter(){
ScheduledExecutorService execService = Executors.newScheduledThreadPool(1);
String streamUri = "/your-get-uri");
long timeout = 500L;
TimeUnit timeUnit = TimeUnit.MILLISECONDS;
MvcResult result = mockMvc.perform(get(streamURI)
.andExpect(request().asyncStarted()).andReturn();
MockAsyncContext asyncContext = (MockAsyncContext) result.getRequest().getAsyncContext();
execService.schedule(() -> {
for (AsyncListener listener : asyncContext.getListeners())
try {
listener.onTimeout(null);
} catch (IOException e) {
e.printStackTrace();
}
}, timeout, timeUnit);
result.getAsyncResult();
// assertions, e.g. response body as string contains "xyz"
mvc.perform(asyncDispatch(result)).andExpect(content().string(containsString("xyz")));
}
I'd like my actor to wait for some event to occur, but I want it to still receive messages and proceed with messages. How can I achieve it?
My code is as follows:
class MyActor extends UntypedActor {
//onReceive implementation etc...
private void doSomething(ActorRef other){
String decision = (String) Await.result(ask(other, new String("getDecision"),1000), Duration.create(1, SECONDS));
while(decision.equals(""){
Thread.sleep(100)
decision = (String) Await.result(ask(other, new String("getDecision"),1000), Duration.create(1, SECONDS));
}
}
}
But this blocks entire actor until it receives proper decision. How can I achieve something like that without blocking my actor ?
That kind of code is the good candidate for the use of Futures.
You can find more information here: http://doc.akka.io/docs/akka/snapshot/java/futures.html
In your case, it would look like:
final ExecutionContext ec = context().dispatcher();
private void doSomething(ActorRef other){
Future<Object> decision = (Patterns.ask(other, new String("getDecision"), 1000));
decision.onSuccess(new OnSuccess<Object>() {
public void onSuccess(Object result) {
String resultString = (String) result;
System.out.println("Decision: " + result);
}
}, ec);
}
You should always try to avoid Await.result which like you said causes the thread to block. You can use callbacks such as onSuccess or onComplete to execute code once the future returns without waiting for the result.