I'm working on a greenfield reactive project where a lot of file handling IO is going on. Is it sufficient if I write the IO code in an imperative blocking manner and then wrap them in a Mono, publish them on boundedElastic scheduler? Will the boundedElastic pool size limit the number of concurrent operations?
If this is not the correct method, can you show an example how to write bytes to a file using Reactor?
Is it sufficient if I write the IO code in an imperative blocking manner and then wrap them in a Mono, publish them on boundedElastic scheduler?
This comes down to opinion on some level - but no, certainly not ideal not for a reactive greenfield project IMHO. boundedElastic() schedulers are great for interfacing with blocking IO when you must, but they're not a good replacement when a true non-blocking solution exists. (Sometimes this is a bit of a moot point with file handling, since it depends if it's possible for the underlying system to do it asynchronously - but usually that's possible these days.)
In your case, I'd look at wrapping AsynchronousFileChannel in a reactive publisher. You'll need to use create() or push() for this and then make explicit calls to the sink, but exactly how you do this depends on your use case. As a "simplest case" for file writing, you could feasibly do something like:
static Mono<Void> writeToFile(AsynchronousFileChannel channel, String content) {
return Mono.create(sink -> {
byte[] bytes = content.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
buffer.put(bytes);
buffer.flip();
channel.write(buffer, 0, null, new CompletionHandler<>() {
#Override
public void completed(Integer result, Object attachment) {
sink.success();
}
#Override
public void failed(Throwable exc, Object attachment) {
sink.error(exc);
}
});
});
}
A more thorough / comprehensive example of bridging the two APIs can be found here - there's almost certainly others around also.
After some researching the java.nio and Spring library I have found the convenient approach to write strings to file as DataBuffers (which perfectly connect with WebFlux) into AsynchronousFileChannel using Spring classes.
It's not "truly" reactive way to write lines in file, but asyncronous and it is still better than using some standard blocking API.
public Mono<Void> writeRows(Flux<String> rowsFlux) {
DefaultDataBufferFactory bufferFactory = new DefaultDataBufferFactory();
CharSequenceEncoder encoder = CharSequenceEncoder.textPlainOnly();
Flux<DataBuffer> dataBufferFlux = rowsFlux.map(line ->
encoder.encodeValue(line, bufferFactory, ResolvableType.NONE, null, null)
);
return DataBufferUtils.write(
dataBufferFlux,
Path.of("/your_path_to_save_file/file.txt"),
StandardOpenOption.CREATE_NEW
);
}
Of course, for better performance in this case you can buffer your strings in flux and then append those strings to one string and create a data buffer from it.
Or if you already have Flux of data buffers you can write them to file using DataBufferUtils directly.
Related
Hi Axon Framework community,
I'd like to have your opinion on how to solve the following problem properly.
My Axon Test Setup
Two instances of the same Spring Boot application (using axon-spring-boot-starter 4.4 without Axon Server)
Every instance publishes the same events on a regular interval
Both instances are connected to the same EventSource (single SQL Server instance using JpaEventStorageEngine)
Every instance is configured to use TrackingEventProcessors
Every instances has the same event handlers registered
What I want to achieve
I'd like that events published by one instance are only handled by the very same instance
If instance1 publishes eventX then only instance1 should handle eventX
What I've tried so far
I can achieve the above scenario using SubscribingEventProcessor. Unfortunately this is not an option in my case, since we'd like to have the option to replay events for rebuilding / adding new query models.
I could assign the event handlers of every instance to differed processing groups. Unfortunately this didn't worked. Maybe because every TrackingEventProcessors instance processes the same EventStream ? - not so sure about this though.
I could implement a MessageHandlerInterceptor which only proceeds in case the event origin is from the same instance. This is what I implemented so far and which works properly:
MessageHandlerInterceptor
class StackEventInterceptor(private val stackProperties: StackProperties) : MessageHandlerInterceptor<EventMessage<*>> {
override fun handle(unitOfWork: UnitOfWork<out EventMessage<*>>?, interceptorChain: InterceptorChain?): Any? {
val stackId = (unitOfWork?.message?.payload as SomeEvent).stackId
if(stackId == stackProperties.id){
interceptorChain?.proceed()
}
return null
}
}
#Configuration
class AxonConfiguration {
#Autowired
fun configure(eventProcessingConfigurer: EventProcessingConfigurer, stackProperties: StackProperties) {
val processingGroup = "processing-group-stack-${stackProperties.id}"
eventProcessingConfigurer.byDefaultAssignTo(processingGroup)
eventProcessingConfigurer.registerHandlerInterceptor(processingGroup) { StackEventInterceptor(stackProperties) }
}
}
Is there a better solution ?
I have the impression that my current solution is properly not the best one, since ideally I'd like that only the event handlers which belongs to a certain instance are triggered by the TrackingEventProcessor instances.
How would you solve that ?
Interesting scenario you're having here #thowimmer.
My first hunch would be to say "use the SubscribingEventProcessor instead".
However, you pointed out that that's not an option in your setup.
I'd argue it's very valuable for others who're in the same scenario to know why that's not an option. So, maybe you can elaborate on that (to be honest, I am curious about that too).
Now for your problem case to ensure events are only handled within the same JVM.
Adding the origin to the events is definitely a step you can take, as this allows for a logical way to filter. "Does this event originate from my.origin()?" If not, you'd just ignore the event and be done with it, simple as that. There is another way to achieve this though, to which I'll come to in a bit.
The place to filter is however what you're looking for mostly I think. But first, I'd like to specify why you need to filter in the first place. As you've noticed, the TrackingEventProcessor (TEP) streams events from a so called StreamableMessageSource. The EventStore is an implementation of such a StreamableMessageSource. As you are storing all events in the same store, well, it'll just stream everything to your TEPs. As your events are part of a single Event Stream, you are required to filter them at some stage. Using a MessageHandlerInterceptor would work, you could even go and write a HandlerEnhacnerDefinition allowing you to add additional behaviour to your Event Handling functions. However you put it though, with the current setup, filtering needs to be done somewhere. The MessageHandlerInterceptor is arguably the simplest place to do this at.
However, there is a different way of dealing with this. Why not segregate your Event Store, into two distinct instances for both applications? Apparently they do not have the need to read from one another, so why share the same Event Store at all? Without knowing further background of your domain, I'd guess you are essentially dealing with applications residing in distinct bounded contexts. Very shortly put, there is zero interest to share everything with both applications/contexts, you just share specifics portions of your domain language very consciously with one another.
Note that support for multiple contexts, using a single communication hub in the middle, is exactly what Axon Server can achieve for you. I am not here to say you cant configure this yourself though, I have done this in the past. But leaving that work to somebody or something else, freeing you from the need to configure infrastructure, that would be a massive timesaver.
Hope this helps you set the context a little of my thoughts on the matter #thowimmer.
Sumup:
Using the same EventStore for both instances is probably no an ideal setup in case we want to use the capabilities of the TrackingEventProcessor.
Options to solve it:
Dedicated (not mirrored) DB instance for each application instance.
Using multiple contexts using AxonServer.
If we decide to solve the problem on application level filtering using MessageHandlerInterceptor is the most simplest solution.
Thanks #Steven for exchanging ideas.
EDIT:
Solution on application level using CorrelationDataProvider & MessageHandlerInterceptor by filtering out events not originated in same process.
AxonConfiguration.kt
const val METADATA_KEY_PROCESS_ID = "pid"
const val PROCESSING_GROUP_PREFIX = "processing-group-pid"
#Configuration
class AxonConfiguration {
#Bean
fun processIdCorrelationDataProvider() = ProcessIdCorrelationDataProvider()
#Autowired
fun configureProcessIdEventHandlerInterceptor(eventProcessingConfigurer: EventProcessingConfigurer) {
val processingGroup = "$PROCESSING_GROUP_PREFIX-${ApplicationPid()}"
eventProcessingConfigurer.byDefaultAssignTo(processingGroup)
eventProcessingConfigurer.registerHandlerInterceptor(processingGroup) { ProcessIdEventHandlerInterceptor() }
}
}
class ProcessIdCorrelationDataProvider() : CorrelationDataProvider {
override fun correlationDataFor(message: Message<*>?): MutableMap<String, *> {
return mutableMapOf(METADATA_KEY_PROCESS_ID to ApplicationPid().toString())
}
}
class ProcessIdEventHandlerInterceptor : MessageHandlerInterceptor<EventMessage<*>> {
override fun handle(unitOfWork: UnitOfWork<out EventMessage<*>>?, interceptorChain: InterceptorChain?) {
val currentPid = ApplicationPid().toString()
val originPid = unitOfWork?.message?.metaData?.get(METADATA_KEY_PROCESS_ID)
if(currentPid == originPid){
interceptorChain?.proceed()
}
}
}
See full demo project on GitHub
I am a newbie to Spring WebFlux and trying to convert my spring MVC application to webflux. I return a Mono mono from my service :
List<Store> stores = new ArrayList();
When I do:
mono.subscribe(stores::addAll);
dataexchange.put("stores", stores);
return Mono.just(dataexchange);
Then stores is populated as empty list in response. However, I can verify that subscribe() is working after returning response.
When I do :
return mono.flatmap( (response) -> {
dataexchange.put("stores", response));
return Mono.just(dataexchange);
});
Then stores is populated in the response.
Can someone please explain me what is the difference between the two? Is flatMap blocking?
Thanks in advance !
mono.subscribe(stores::addAll);
is asynchronous. That means, you tell the mono that it can now start evaluating.
What you do is continue processing stores right away - with a huge chance that the Mono hasn't evaluated yet.
So, how can you fix this?
You can block until the Mono has completed:
mono.doOnNext(stores::addAll).block()
Of course, this defeats the purpose of reactive programming. You are blocking the main thread until an action completes, which can be achieved without Reactor in a much simpler fashion.
The right way is to change the rest of your code to be reactive too, from head to toe. This is similar to your second example, where your call to dataexchange is part of the Mono, thus being evaluated asynchronously, too.
The important lesson to be learned is that operations like map or flatMap are not operating on the result of the Mono, but create a new Mono that adds another transformation to the execution of the original Mono. As long as the Mono doesn't evaluate, the flatMap or map operations are not actually doing anything.
I hope this helps.
Looking how to build something similar in Swift 3.
I'm used to using this sort of architecture in Unity3d, perhaps there isn't anything similar to handle async data. I've heard of completion blocks + using protocols/delegates to pass data in Swift but I thought it'd be easier to have a public function that gets the data and then use a coroutine to wait until all the data is in the VC to start things up.
Here is C# code I'd use to create them:
List<Int> data = new List<Int>;
private IENumerator get_data()
{
run_async_func_to_get_data();
while(data.count == 0)
{
yield return null;
}
yield break;
}
private IENumerator start_game()
{
yield return get_data();
yield return use_data();
}
void Start()
{
StartCoroutine(start_game);
}
No, Swift do not currently support Unity/C# style coroutines (i.e., yield return style constructs). Such feature is pretty cool by the way ;-)
Having said that, you might want to take a look in the Async framework for a somewhat valid alternative (if you are really looking for async/await abstractions):
Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch
As for Swift native support, we might need to wait for Swift ≥ 5 for something like that to come along:
Actors, async/await, atomicity, memory model, and related topics. This area is highly desired by everyone, as it will open the door for all sorts of new things on the client, server and more. We plan to start formal discussions about this in Phase 2, but it is unfortunately crystal clear that a new concurrency model won’t be done in time for the Swift 4 release. This is simply because it will take more than a 12 months to design and build, and we want to make sure to take time to do it right. It also makes sense for the memory ownership model to be better understood before taking this on.
I am new to Vert.X.
Does Vert.x have a built in facility for centralized filters? What I mean are the kind of filters that you would use on a J2EE application.
For instance, all pages have to go through the auth filter, or something like that.
Is there a standardized way to achieve this in Vert.x?
I know this question is quite old, but for those still looking for filter in Vertx 3, the solution is to use subRouter as a filter:
// Your regular routes
router.route("/").handler((ctx) -> {
ctx.response().end("...");
});
// Have more routes here...
Router filterRouter = Router.router(vertx);
filterRouter.get().handler((ctx)->{
// Do something smart
// Forward to your actual router
ctx.next();
});
filterRouter.mountSubRouter("/", router);
Filtering is an implementation of the chain of responsibility in the servlet container. Vert.x does not have this kind of concept but with yoke (or apex in the new release) you are able to easily reproduce this behavior.
Give a look in the routing section: https://github.com/vert-x3/vertx-web/blob/master/vertx-web/src/main/asciidoc/index.adoc
HTH,
Carlo
Vert.x is unopinionated about how many things should be handled. But generally speaking, these types of features are typically implemented as "bus mods" (i.e. modules/verticles which receive input and produce output over the event bus) in Vert.x 2. In fact, the auth manager module may help you get a better understanding of how this is done:
https://github.com/vert-x/mod-auth-mgr
In Vert.x 3 the module system will be/is gone, but the pattern will remain the same. It's possible that some higher level framework built on Vert.x could support these types of filters, but Vert.x core will not.
If also recommend you poke around in Vert.x Apex if you're getting started building web applications on Vert.x:
https://github.com/vert-x3/vertx-apex
Vert.x is more similar to node.js than any other java based frameworks.
Vert.x depends on middlewares. You can define them and attach them to a route. Depending on the order they are defined in they will get called.
For example lets say you have a user application where you would like to run logging and request verification before the controller is called.
You can do something like follows:
Router router = Router.router(vertx);
router.route("/*").handler(BodyHandler.create()); // Allows Body to available in post calls
router.route().handler(new Handler<RoutingContext>() {
#Override
public void handle(RoutingContext event) {
//Handle logs
}
})
router.route("/user").handler(new Handler<RoutingContext>() {
#Override
public void handle(RoutingContext event) {
// handle verification for all apis starting with /user
}
});
Here depending on the route set of middleware will get called.
From my POV, this is exactly the opposite to what vert.x tries to achieve. A verticle being the core building block of the framework is supposed to keep the functions distributed, rather than centralized.
For the multithreaded (cluster) async environment that makes sense, because as soon as you start introducing something "centralized" (and usually synchronous), you would lose the async ability.
One of the options is to implement auth in your case would be to exchange the messages with respecive auth-verticle over the event bus. In this case you would have to handle the async aspect of such a request.
I have been using Rx for a while now for Events on my projects and dedicatedly for Socket programming and the good part is its doing well. Managing my code, performance advantage and much better to execute and interpret.
Lately I have to modify my project's process flow where i need to dump all the incoming data (from socket operations) into queues (using MSMQ implementation as decided for queueing).
As MSMQ provides async call for dequeing messages from the queue (but in an wierd pattern).
I have been struggling to use Rx for this purpose now, but enable to do so.
Question : Can some one give me a clean code example to implement Rx for message receiving from queue using Async pattern.
I need the async operator implementation for MSMQ analogous to something like this
var data = Observable.FromAsyncPattern<byte[]>(
this.receiverSocket.BeginReceive,
this.receiverSocket.EndReceive(some parameters);
Thanks in advance. *cheers* to Rx and .NET
It would be as simple as:
var queue = new System.Messaging.MessageQueue("test");
var fun = Observable.FromAsyncPattern((cb, obj) => queue.BeginReceive(TimeSpan.FromMinutes(10),obj,cb), a => queue.EndReceive(a));
var obs = fun();