I want to know if it is possible to have only one node in a cluster environement for our Liferay 7.1 in localhost.
Here is a part of my portal-ext :
cluster.link.enabled=true
cluster.link.channel.properties.control=/custom_jgroups/tcp.xml
cluster.link.channel.properties.transport.0=/custom_jgroups/tcp.xml
I set following properties on VM Options for my tomcat :
-Djgroups.bind_addr=127.0.0.1
-Djgroups.tcpping.initial_hosts=127.0.0.1[7800]
In a portlet I do to execute manually a job :
Message message = new Message();
message.put(SchedulerEngine.JOB_NAME, job);
message.put(SchedulerEngine.GROUP_NAME , job);
message.put(SchedulerEngine.DESTINATION_NAME, DestinationNames.SCHEDULER_DISPATCH);
message.setDestinationName(DestinationNames.SCHEDULER_DISPATCH);
log.info("Stream " + streamNumber + " is launched ("+job+")");
try {
ClusterLinkUtil.sendMulticastMessage(message, Priority.LEVEL10);
} catch (Exception e){
log.error(e);
}
In production with two nodes in my cluster it works but in test with one node, nothing happens.
Here is the log debug. It appears that message is sent but not received ... Any ideas ?
DEBUG [http-nio-8080-exec-6][ClusterLinkImpl:131] Select channel number 0 for priority LEVEL10
DEBUG [http-nio-8080-exec-6][JGroupsClusterChannel:171] Send multicast message {destinationName=liferay/scheduler_dispatch, response=null, responseDestinationName=null, responseId=null, payload=null, values={GROUP_NAME=com.job.UselessDataPurgeJob, DESTINATION_NAME=liferay/scheduler_dispatch, JOB_NAME=com.job.UselessDataPurgeJob}}
Related
At work we have some code in a Azure WebJob where we use Rabbit
The basic workflow is this
A message arrives on RabbitMQ Queue
We have a message handler for the incoming message
Within the message handler we start a top level (user) supervisor actor where we "ask" it to handle the message
The supervisor actor hierarchy is like this
And the relevant top level code is something like this (this is the WebJob code)
static void Main(string[] args)
{
try
{
//Bootstrap akka IoC resolver well ahead of any actor usages
new AutoFacDependencyResolver(ContainerOperations.Instance.Container, ContainerOperations.Instance.Container.Resolve<ActorSystem>());
var system = ContainerOperations.Instance.Container.Resolve<ActorSystem>();
var busQueueReader = ContainerOperations.Instance.Container.Resolve<IBusQueueReader>();
var dateTime = ContainerOperations.Instance.Container.Resolve<IDateTime>();
busQueueReader.AddHandler<ProgramCalculationMessage>("RabbitQueue", x =>
{
//This is code that gets called whenever we have a RabbitMQ message arrive
//This is code that gets called whenever we have a RabbitMQ message arrive
//This is code that gets called whenever we have a RabbitMQ message arrive
//This is code that gets called whenever we have a RabbitMQ message arrive
//This is code that gets called whenever we have a RabbitMQ message arrive
try
{
//SupervisorActor is a singleton
var supervisorActor = ContainerOperations.Instance.Container.ResolveNamed<IActorRef>("SupervisorActor");
var actorMessage = new SomeActorMessage();
var supervisorRunTask = runModelSupervisorActor.Ask(actorMessage, TimeSpan.FromMinutes(25));
//we want to wait this guy out
var supervisorRunResult = supervisorRunTask.GetAwaiter().GetResult();
switch (supervisorRunResult)
{
case CompletedEvent completed:
{
break;
}
case FailedEvent failed:
{
throw failed.Exception;
}
}
}
catch (Exception ex)
{
_log.Error(ex, "Error found in Webjob");
//throw it for the actual RabbitMqQueueReader Handler so message gets NACK
throw;
}
});
Thread.Sleep(Timeout.Infinite);
}
catch (Exception ex)
{
_log.Error(ex, "Error found");
throw;
}
}
And this is the relevant IOC code (we are using Autofac + Akka.NET DI for Autofac)
builder.RegisterType<SupervisorActor>();
_actorSystem = new Lazy<ActorSystem>(() =>
{
var akkaconf = ActorUtil.LoadConfig(_akkaConfigPath).WithFallback(ConfigurationFactory.Default());
return ActorSystem.Create("WebJobSystem", akkaconf);
});
builder.Register<ActorSystem>(cont => _actorSystem.Value);
builder.Register(cont =>
{
var system = cont.Resolve<ActorSystem>();
return system.ActorOf(system.DI().Props<SupervisorActor>(),"SupervisorActor");
})
.SingleInstance()
.Named<IActorRef>("SupervisorActor");
The problem
So the code is working fine and doing what we want it to, apart from the Akka.Net "ask" timeout shown above in the WebJob code.
Annoyingly this seems to work fine if I try and run the webjob locally. Where I can simulate a "ask" timeout by providing a new supervisorActor that simply doesn't EVER respond with a message back to the "Sender".
This works perfectly running on my machine, but when we run this code in Azure, we DO NOT see a Timeout for the "ask" even though one of our workflow runs exceeded the "ask" timeout by a mile.
I just don't know what could be causing this behavior, does anyone have any ideas?
Could there be some Azure specific config value for the WebJob that I need to set.
The answer to this was to use the async rabbit handlers which apparently came out in V5.0 of the C# rabbit client. The offical docs still show the sync usage (sadly).
This article is quite good : https://gigi.nullneuron.net/gigilabs/asynchronous-rabbitmq-consumers-in-net/
Once we did this, all was good
I am able to handle and report connection/ authentication related errors for imap and pop adapter by using error-channel on the poller.
I have one for imap-idle too but its not getting these error on that channel but a warning in the logs only.
what is the way out to handle and report similar errors for email idle adapter?
I guess you mean this peace of code:
catch (Exception e) { //run again after a delay
logger.warn("Failed to execute IDLE task. Will attempt to resubmit in " + ImapIdleChannelAdapter.this.reconnectDelay + " milliseconds.", e);
ImapIdleChannelAdapter.this.receivingTaskTrigger.delayNextExecution();
ImapIdleChannelAdapter.this.publishException(e);
}
And you see that WARN in your logs.
Pay attention, please, to the latest line about publishException(). It is this code:
private void publishException(Exception e) {
if (this.applicationEventPublisher != null) {
this.applicationEventPublisher.publishEvent(new ImapIdleExceptionEvent(e));
}
So, what you need is to add an EventListener for that ImapIdleExceptionEvent. For example you can use ApplicationEventListeningMessageProducer.
We have an application with around 75 partitioned steps spread around 100 jobs. Our configuration for the outbound gateway is:
<int-jms:outbound-gateway
id="outbound-gateway_1"
auto-startup="true"
connection-factory="jmsConnectionFactory"
request-channel="jms.requests_1"
request-destination="jms.requestsQueue"
reply-channel="jms.reply_1"
reply-destination="jms.repliesQueue"
receive-timeout="${timeout}"
correlation-key="JMSCorrelationID" >
<int-jms:reply-listener receive-timeout="1000"/>
</int-jms:outbound-gateway>
When autostart="true" we see the replyListener thread for each outbound gateway. To remove this extra load and resource consumption, we change to autostart="false" and added a step listener for the partitioned step the start and stop the gateway in the beforeStep and afterStep methods. At server startup the replyListener threads are not there as expected. They appear during step execution but are not removed after the call to stop on the outbound gateway (even after waiting a prolonged period).
Is something else needed to cleanup the replyListener?
OK, I see what you mean. That looks like:
while ((active = isActive()) && !isRunning()) {
if (interrupted) {
throw new IllegalStateException("Thread was interrupted while waiting for " +
"a restart of the listener container, but container is still stopped");
}
if (!wasWaiting) {
decreaseActiveInvokerCount();
}
wasWaiting = true;
try {
lifecycleMonitor.wait();
}
catch (InterruptedException ex) {
// Re-interrupt current thread, to allow other threads to react.
Thread.currentThread().interrupt();
interrupted = true;
}
}
in the DefaultMessageListenerContainer.AsyncMessageListenerInvoker.executeOngoingLoop()
The point there is lifecycleMonitor.wait(); and pay attention to the message of the IllegalStateException.
Not sure what is the purpose of such a design, but we dontt have choice unless live with that as is.
Further the logic in the start() is based on the this.pausedTasks local cache, which is filled during doInitialize() if container !this.running.
Feel free to raise a JIRA, if you think that logic must be changed somehow.
According to node.js documentation, the cluster class should have a workers object and it can be iterated like this:
Object.keys(cluster.workers).forEach((id) => {
cluster.workers[id].on('message', messageHandler);
});
but for some reason when I try this in my code, cluster.workers is undefined (process launched with pm2)
var cluster = require("cluster");
console.log("cluster status : " , cluster.isMaster ? " master " : " slave " , " - worker id " , (cluster.worker ? cluster.worker.id : " none ") , " workers : " , cluster.workers);
I got output like this:
cluster status : slave - worker id 15 workers : undefined
cluster status : slave - worker id 14 workers : undefined
so I guess workers are only available from master , but is there a way to communicate with other slaves for a slave ?
You're right, the 'workers' property is only available in the master process (see latest documentation).
I don't think there's any way for workers to communicate directly with each other - all communication goes via the master.
You can pretty easily use the 'message' mechanism to set up a system for using the master as a relay to route messages between workers. I'm not sure quite what you're trying to achieve, but here's an overview.
The idea of the first chunk of code that you posted is that you run it in the master and it means that the "messageHandler" callback is called when the master receives a message from any of its workers. In fact, you can achieve the same thing by doing:
cluster.on('message', messageHandler);
The messageHandler function is passed a parameter identifying which worker sent the message.
Similarly, workers can listen for messages from the master by doing this:
process.on('message', workerMessageHandler);
You can send messages by doing:
// Worker: send message to master
process.send({ cmd: 'notifyRequest', data: 'somedata' });
// Master: send message to specific workers
worker.send({ data: 'somedata' });
cluster.workers[0].send({ whatever: 'something' });
The message can be a string or an object (which will be serialized to JSON).
I heve the next lines of code:
_printJob = new PrintJob();
if (_printJob.start2(null, _printWorkSettings.usePageSetupDialog)) {
MonsterDebugger.trace(this, new Date());
try {
_printJob.addPage(objectoToPrint, null, _printWorkSettings.jobOptions);
} catch (error:Error) {
MonsterDebugger.trace(this, error + "/n" + error.getStackTrace() + "/n" + error.toString());
}
_printJob.send();
MonsterDebugger.trace(this, 'job sended to printer');
MonsterDebugger.trace(this, new Date());
}
When it is executed on a Linux machine running AIR 2.5 I get the error 2057, the I check the time between the start2 method and the send and is on the same second. I also checked that the property objectToPrint is a MovieClip.
This works on a windows PC, and I'm unable to do a better debugging than the one is possible using the trace of MonsterDebugger, so any ideas on how can I get more information about why addPage is returning this error or any information about the printJob on Linux?
By the way, I also tryed:
_printJob.addPage(objectoToPrint);
And I get the same result.
The property _printWorkSettings.usePageSetupDialog is always true so I now showing the print menu for the user.
Thansk in advance folks :)
I found the problem, there is only one printer on the linux system and was not setted a default so addpage trowh errors.
I get a inspiration on this forum