Spring Integration ExecutorChannel running on Same Caller Thread - spring-integration

Need to process messages sequentially, irrespective of the spring.task.scheduling.pool.size threads defined. Hence, we defined a ExecutorChannel with single thread. However, we see the messages are processed parallelly by the caller's thread. Please suggest how to process the messages sequentially without blocking the caller thread.
#Bean
public MessageChannel svcErrorChannel() {
return new ExecutorChannel(Executors.newSingleThreadExecutor());
}
return IntegrationFlows.from(svcErrorChannel())
.log(ERROR, m -> "ErrorFlow Initiated: " + m.getPayload())
Application Logs:
2023-02-04 20:21:03,407 [boundedElastic-1 ] ERROR o.s.i.h.LoggingHandler - 1c710133ada428f0 ErrorFlow Initiated: org.springframework.messaging.MessageHandlingException: xxxxxxxxxxxxxxxx
2023-02-04 20:21:03,407 [boundedElastic-2 ] ERROR o.s.i.h.LoggingHandler - 1c710133ada428f0 ErrorFlow Initiated: org.springframework.messaging.MessageHandlingException: xxxxxxxxxxxxxxxxx

The log() operator is essentially a ChannelInterceptor where that logging happens in a preSend() hook - the part of a MessageChannel on producer side. Therefore it is expected to see your Reactor threads in those logs.
If you really would like to log consumed (not produced) messages, then you need to use a .handle(new LoggingHandler()) instead of log() operator. Or you can use a .bridge() before your log().
See docs for more info: https://docs.spring.io/spring-integration/reference/html/dsl.html#java-dsl-log

Related

How to schedule a task in Shopware 6

I have created a custom scheduled task. I have registered it as well using the following tutorial:
https://developer.shopware.com/docs/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task#overview
However, in my database, the status of this task is still "queued" instead of "scheduled". This stops the task from executing. How to fix this? I am currently working on localhost.
Status queued means that a message to execute that task was dispatched to the message queue. If the status does not change automatically that indicates that now worker executed the messages from the queue.
By default (for dev setups!) there is a AdminWorker, which will poll and execute messages from the queue as long as the shopware administration is open in a browser. You can also start a worker manually per CLI:
bin/console messenger:consume
You can find more information how to work with the message queue and how to start workers in the official docs.
I had exactly the same problem.
After I had created and registered my task, it was displayed in the database as "queued" and accordingly not executed.
By manually changing it to "scheduled" it was then executed once and set back to "queued".
Of course unusable for productive use.
My error was the following:
In the services.xml I had passed additional parameters for my handler.
Accordingly my handler had a __construct() method.
However, the class inherits from "ScheduledTaskHandler" which in turn also has a constructor and expects the parameter "scheduledTaskRepository".
This repository is used to update the status.
The solution:
inject the service scheduled_task.repository in the services.xml into your custom handler
call in the construct method of the handler: parent::__construct($scheduledTaskRepository);.
In the end it should like this:
<?php declare(strict_types=1);
class myCustomHandler extends ScheduledTaskHandler
{
public function __construct(
EntityRepository $scheduledTaskRepository,
[...]
) {
parent::__construct($scheduledTaskRepository);
[...]
}
public static function getHandledMessages(): iterable
{
return [ MyCustomTask::class ];
}
public function run(): void
{
file_put_contents('test.txt', 'test');
}
}

Spring Integration DSL - composition with gateway blocks thread

I am trying to learn about how to build IntegrationFlows as units, and join them up.
I set up a very simple processing integration flow:
IntegrationFlow processingFlow = f -> f
.<String>handle((p, h) -> process(p))
.log();
flowContext.registration(processingFlow)
.id("testProcessing")
.autoStartup(false)
.register();
Processing is very simple:
public String process(String process) {
return process + " has been processed";
}
Then I compose a flow from a source, using .gateway() to join the source to the processing:
MessageChannel beginningChannel = MessageChannels.direct("beginning").get();
StandardIntegrationFlow composedFlow = IntegrationFlows
.from(beginningChannel)
.gateway(processingFlow)
.log()
.get();
flowContext.registration(composedFlow)
.id("testComposed")
.autoStartup(false)
.addBean(processingFlow)
.register();
Then I start the flow and send a couple of messages:
composedFlow.start();
beginningChannel.send(MessageBuilder.withPayload(new String("first string")).build());
beginningChannel.send(MessageBuilder.withPayload(new String("second string")).build());
The logging handler confirms the handle method has been called for the first message, but the main thread then sits idle, and the second message is never processed.
Is this not the correct way to compose integration flow from building blocks? Doing so with channels requires registering the channel as a bean, and I'm trying to do all this dynamically.
It must be logAndReply() in the processingFlow. See their JavaDocs for difference. The log() in the end of flow makes it one-way. That’s why you are blocked since gateway waits for reply, but there is no one according your current flow definition. Unfortunately we can’t determine that from the framework level: there might be cases when you indeed don’t return according some routing or filtering logic. The gateway can be configured with a reply timeout. By default it is an infinite.

Right way to start a worker thread with Quarkus?

I am implementing a Quarkus server. On server start, a (never ending) background process should be started.
I know I can observe the start event with an #ApplicationScopedbean which implements:
void onStart(#Observes StartupEvent ev).
But what is the best way to start a background process? Are there restrictions?
In J2EE one should not create Threads, but use ManagedExecutorService or an EJB with a #Asynchronous annotated method.
Is there something similar in Quarkus? I only found the scheduler annotations (which are nice, but I want to start a process only once at the beginning).
So can I just create threads? Or just put my infinite code in void onStart(#Observes StartupEvent ev) ?
Thank you
As in EJB you should not do such things with a background process. Such processes that are "out of control" of the framework cause most of time very annoying problems.
The answer is: It depends on what you want to do in that job.
If you want to execute tasks on a regular base you could use timers.
If you want to use it as an asynchronous worker, you can use a message queue.
Both is most easily done with the vert.x integration into Quarkus.
Use #ConsumeEvent to create a queue, use
#Inject
EventBus bus;
bus.send("Example message");
to send messages.
Use #Scheduled to work on regular jobs, like in this example.
If you need to permanently listen to some socket or file it is getting more difficult. Maybe the websockets will be helpful in this case.
The easiest way to start a worker thread is using Vertx#executeBlocking, like this:
#Inject
Vertx vertx;
void foo() {
vertx.<String>executeBlocking(promise -> {
// This code will be executed in a worker thread
System.out.println("Thread: " + Thread.currentThread());
promise.complete("Done");
}, asyncResult -> {
System.out.println(asyncResult.result()); // Done
});
}
If it will be a long running thread maybe it's a good idea not to use the default worker thread pool and create a new one:
...
#PostConstruct
void init() {
this.executor = vertx.createSharedWorkerExecutor("my-worker", 10);
}
void foo() {
executor.<String>executeBlocking(promise -> {
...
}
}
Other way of doing this is using a Verticle.

Safe fire and forget method in Perl

I need to execute a method (not process) asynchronously in my Perl code, but I must ensure that this code will never raise any exception and stop my main task execution.
What would be the best way to call a method asynchronously and silencing any potential exception whether it is the called method internal exception whether it is an threading exception?
In Java we would had something like this:
// my task runs here
try {
// assyncrounous method invocation (fire and forget)
new MyThread().start();
} catch (Throwable e) {
// Silent any error
}
// my task continues here
You have two options if you want to execute arbitrary code asynchronously: You can run it in a separate process, or you can run it in a separate thread. Using a separate process would make even more robust, but you could use a thread.
use threads;
my $thread = async { code() };
join the thread to wait for it to finish.

Spring MessageTemplate Issue

I'm facing a problem after the migration from Spring 2.5, Flex 3.5, BlazeDS 3 and Java 6 to Spring 3.1, Flex 4.5, BlazeDS 4 and Java 7. I've declared a ClientFeed in order to send a sort of "alarm" messages to the flex client. There are three methods those alarms are sent. The first one is via snmp traps, a thread is started and wait for any trap, as one is received an alarm will be sent. The second method is via a polling mechanism, at the beginning of the web application a thread is started and will poll after a constant amount of time the alarms and send them to the client. The third method is the explicit poll command from the user, this will call a specific function on the dedicated service. This function uses then the same algorithm used in the second methods to perform a poll and shall send those alarms to the client.
The problem is that after the migration the first two methods are working without a problem, but the third one doesn't. I suspect there is a relation with the threads. Is there any known issue between messagetemplate and the threads with the new frameworks ?
Here is a snapshot of the used client feed:
#Component
public class ClientFeed {
private MessageTemplate messageTemplate;
#Autowired
public void setTemplate(MessageTemplate messageTemplate) {
this.messageTemplate = messageTemplate;
}
public void sendAlarmUpdate(final Alarm myAlarm) {
if (messageTemplate != null) {
System.out.println("Debug Thread: " + Thread.currentThread().getName());
messageTemplate.send(new AsyncMessageCreator() {
public AsyncMessage createMessage() {
AsyncMessage msg = messageTemplate.createMessageForDestination("flexClientFeed");
msg.setHeader("DSSubtopic", "Alarm");
msg.setBody(myAlarm);
return msg;
}
});
}
}
}
By the three methods I reach this piece of code and the displayed thread name are respectively: "Thread-14", "Thread-24" and "http-bio-80-exec-10".
I solved the problem by creating a local thread on the server to perform the job. Therewith the client feed is called via this new created thread instead of the http-thread.

Resources